Httplistener с поддержкой HTTPS

Кажется, есть много запутанной, иногда противоречивой информации, касающейся возможности .NET HTTPListener HTTPS. Мое понимание таково:

  • Для одного кода С# требуется префикс https (например, https://*:8443), чтобы слушатель мог понять, что ему нужно обслуживать запросы SSL на этом порту.

  • Фактическое рукопожатие SSL происходит под прикрытием и обрабатывается http.sys (похоронен где-то на машине Windows). Код С# не должен явно управлять рукопожатием SSL, потому что это происходит под прикрытием.

  • Нужно иметь "доверенный сертификат X.509" на машине httpListener, и каким-то образом этот сертификат должен быть привязан к порту 8443 (в этом примере).

Правильно ли мое понимание выше? Если нет, пожалуйста, просветите меня.

Что касается сертификатов X.509, я понимаю следующее:

  • Используйте makecert для создания сертификата X.509. Этот сертификат хранится в личном хранилище и должен быть перемещен в доверенное хранилище (именно здесь будет искать HTTP-слушатель). Кажется, я могу использовать certMgr, чтобы выполнить движение, или я могу использовать mmc, чтобы произвести движение. Кажется, существует более одного формата сертификата X.509 (DER, Base64, pks, защищенный pswd, pks закрытый и т.д.)... Есть ли предпочтительный формат, который я должен использовать?

Как только я получу сертификат в доверенное хранилище, мне нужно привязать его к порту TCP. Я нахожусь на Windows 7: я должен использовать httpcfg или netsh?

Ответ 1

Я сделал кучу домашних заданий и получил эту работу. Шаги для добавления поддержки SSL для .NET HttpListener:

  1. Обновите код приложения С#, включив в него префикс https. Пример:

    String[] prefixes = { "http://*:8089/","https://*:8443/" };
    

    Это с точки зрения кода.

  2. Что касается сертификатов, используйте командную консоль Windows SDK (также можно использовать командную консоль Visual Studio Professional)

    • Используйте makecert.exe для создания центра сертификации. Пример:

      makecert -n "CN=vMargeCA" -r -sv vMargeCA.pvk vMargeCA.cer
      
    • Используйте makecert.exe для создания сертификата SSL

      makecert -sk vMargeSignedByCA -iv vMargeCA.pvk -n "CN=vMargeSignedByCA" -ic vMargeCA.cer vMargeSignedByCA.cer -sr localmachine -ss My

    • Используйте MMC GUI для установки CA в хранилище Trusted Authority

    • Используйте MMC GUI для установки SSL-сертификата в личном хранилище
    • Свяжите сертификат с IP address:port и приложением. Пример:

      netsh http add sslcert ipport=0.0.0.0:8443 certhash=585947f104b5bce53239f02d1c6fed06832f47dc appid={df8c8073-5a4b-4810-b469-5975a9c95230}

      Certhash - это отпечаток вашего SSL-сертификата. Вы можете найти это используя mmc. Appid находится в Visual Studio... обычно в файле Assembly.cs, найдите значение GUID.

Могут быть и другие способы выполнения вышесказанного, но это сработало для меня.

Ответ 2

Ниже подробно описаны шаги, которые я выполнил, чтобы настроить автономный сервер в Windows, используя OpenSSL для создания самозаверяющего сертификата для приложения С# HTTPListener. Он содержит множество ссылок на случай, если вы захотите провести дальнейшие исследования.

  1. Создайте автономный сервер в .NET через HttpListener:

    var prefixes = {"http://localhost:8080/app/root", "https://localhost:8443/app/root"};
    var listener = new HttpListener();
    foreach (string s in prefixes)
        listener.Prefixes.Add(s);
    listener.Start();
    
  2. Создать самозаверяющий сертификат: *

    1. openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365, который запросит у вас значение каждого из полей сертификата в командной строке. В качестве общего имени введите имя домена (например, localhost)
    2. openssl pkcs12 -inkey bob_key.pem -in bob_cert.cert -export -out bob_pfx.pfx, чтобы его можно было импортировать с помощью своего ключа на целевой компьютер.

    * Для альтернативного использования makecert см. собственный Уолтер ответ.

  3. Откройте диспетчер сертификатов для локального компьютера. Когда вы запускаете certmgr.msc, он открывает Диспетчер сертификатов для текущего пользователя, что здесь не то, что нам нужно. Вместо этого:

    1. Из административной командной строки на целевом компьютере запустите mmc
    2. Нажмите Ctrl + M или нажмите File > Add/Remove Snap-in
    3. Выберите Certificates и нажмите Add >
    4. В появившемся диалоговом окне выберите Computer Account и нажмите Next
    5. Выберите Local Computer. Нажмите Finish, затем Okay
  4. Импортируйте сертификат (pfx) в Хранилище сертификатов Windows на целевом компьютере

    1. В ранее открытом окне mmc перейдите к Certificates (Local Computer) > Personal
    2. Щелкните правой кнопкой мыши Personal, затем нажмите All Tasks -> Import...
    3. На втором экране диалогового окна найдите и импортируйте свой сертификат. Вам нужно изменить фильтр типов файлов на Personal Information Exchange или All Files, чтобы найти его
    4. На следующем экране введите пароль, выбранный на шаге 2.1, и обратите особое внимание на первый флажок. Это определяет, насколько надежно хранится ваш сертификат, а также насколько удобно его использовать
    5. На последнем экране выберите Place all certificates in the following store. Убедитесь, что написано Personal, затем нажмите Finish
    6. Повторите описанную выше процедуру импорта для раздела сертификатов Trusted Root Certification Authorities.
  5. Создайте ассоциации портов для вашего приложения. В Windows Vista и более поздних версиях используйте netsh, как и я. (Для Windows XP и более ранних версий используйте httpcfg)

    • В административной командной строке введите следующее, чтобы установить привязку SSL* к вашему приложению и соответствующий порт. Примечание: Эту команду легко ошибиться, поскольку (в PowerShell) скобки необходимо экранировать. Будет работать следующая команда PowerShell:

      netsh http add sslcert ipport=0.0.0.0:8443 '
          certhash=110000000000003ed9cd0c315bbb6dc1c08da5e6 '
          appid='{00112233-4455-6677-8899-AABBCCDDEEFF'}
      

      Для cmd.exe следует использовать следующее:

      netsh http add sslcert ipport=0.0.0.0:8443 certhash=110000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
      
      • Параметр ipport приведет к привязке сертификата SSL к порту 8443 на каждом сетевом интерфейсе; для привязки к определенному интерфейсу (только) выберите IP-адрес, связанный с этим сетевым интерфейсом.
      • certhash - это просто отпечаток сертификата с удаленными пробелами
      • appid - это GUID, хранящийся в информации о сборке вашего приложения. (Примечание: механизм netsh, очевидно, является интерфейсом COM, судя по этому вопросу и его ответам)

      * Microsoft перенаправила ссылку привязки SSL с здесь на там.

  6. Запустите свой веб-сервер, и все готово!

Ответ 3

Поскольку ваши собственные самоподписанные сертификаты в ответах не работали для меня, и поскольку в этом вопросе конкретно содержится призыв к созданию https-сервера HTTP.ListListener и запрашивается какие-либо советы/рекомендации, я хочу поделиться своим подходом. hostname, что-то вроде www.made-up.com, которое должно указывать на ваш WAN IP (например, спросите у своего поставщика хоста инструкции) и переместите его порт, например 443 на ваш локальный компьютер. Не забудьте открыть этот входящий порт 443 в своем брандмауэре вашей локальной машины.

Я использовал https://letsencrypt.org/. В Windows это не так просто, как на Linux, потому что нет официального сертификата ACME certbot для окон. Однако вы можете использовать https://github.com/Lone-Coder/letsencrypt-win-simple, из которых также существуют двоичные файлы. Однако "В настоящее время поддерживается только IIS". Но вы можете легко обмануть его, чтобы создать сертификат на вашем компьютере, чтобы вы могли приблизиться к своему httplistener по протоколу SSL:

  • Установите IIS (через функции Windows в/из), создайте веб-сайт в IIS и назначьте имя хоста. Также создайте безопасный (443-портовый) веб-сайт.
  • Run letencrypt-win-simple exe (я использовал версию 1.9.1). Ответьте на вопросы, чтобы они могли сгенерировать сертификат.
  • После этого вы можете остановить IIS-сервер.

Я считаю, что вы должны принять к сведению задание обновления, поскольку я не уверен, что это произойдет через несколько месяцев (вам, вероятно, придется снова запустить IIS для обновления сертификата).

Ответ 4

Мы можем импортировать сертификаты, используя PowerShell и С# (ручные действия не требуются).

Для получения дополнительной информации см.: https://blog.davidchristiansen.com/2016/09/howto-create-self-signed-certificates-with-powershell/

Я использую этот код:

/// <summary>
/// Create and install a self-signed certificate for HTTPS use
/// </summary>
private static void CreateInstallCert(int expDate, string password, string issuedBy)
{
    // Create/install certificate
    using (var powerShell = System.Management.Automation.PowerShell.Create())
    {
        var notAfter = DateTime.Now.AddYears(expDate).ToLongDateString();
        var assemPath = Assembly.GetCallingAssembly().Location;
        var fileInfo = new FileInfo(assemPath);
        var saveDir = Path.Combine(fileInfo.Directory.FullName, "CertDir");
        if (!Directory.Exists(saveDir))
        {
            Directory.CreateDirectory(saveDir);
        }

        // This adds certificate to Personal and Intermediate Certification Authority
        var rootAuthorityName = "My-RootAuthority";
        var rootFriendlyName = "My Root Authority";
        var rootAuthorityScript =
            $"$rootAuthority = New-SelfSignedCertificate" +
            $" -DnsName '{rootAuthorityName}'" +
            $" -NotAfter '{notAfter}'" +
            $" -CertStoreLocation cert:\\LocalMachine\\My" +
            $" -FriendlyName '{rootFriendlyName}'" +
            $" -KeyUsage DigitalSignature,CertSign";
        powerShell.AddScript(rootAuthorityScript);

        // Export CRT file
        var rootAuthorityCrtPath = Path.Combine(saveDir, "MyRootAuthority.crt");
        var exportAuthorityCrtScript =
            $"$rootAuthorityPath = 'cert:\\localMachine\\my\\' + $rootAuthority.thumbprint;" +
            $"Export-Certificate" +
            $" -Cert $rootAuthorityPath" +
            $" -FilePath {rootAuthorityCrtPath}";
        powerShell.AddScript(exportAuthorityCrtScript);

        // Export PFX file
        var rootAuthorityPfxPath = Path.Combine(saveDir, "MyRootAuthority.pfx");
        var exportAuthorityPfxScript =
            $"$pwd = ConvertTo-SecureString -String '{password}' -Force -AsPlainText;" +
            $"Export-PfxCertificate" +
            $" -Cert $rootAuthorityPath" +
            $" -FilePath '{rootAuthorityPfxPath}'" +
            $" -Password $pwd";
        powerShell.AddScript(exportAuthorityPfxScript);

        // Create the self-signed certificate, signed using the above certificate
        var gatewayAuthorityName = "My-Service";
        var gatewayFriendlyName = "My Service";
        var gatewayAuthorityScript =
            $"$rootcert = ( Get-ChildItem -Path $rootAuthorityPath );" +
            $"$gatewayCert = New-SelfSignedCertificate" +
            $" -DnsName '{gatewayAuthorityName}'" +
            $" -NotAfter '{notAfter}'" +
            $" -certstorelocation cert:\\localmachine\\my" +
            $" -Signer $rootcert" +
            $" -FriendlyName '{gatewayFriendlyName}'" +
            $" -KeyUsage KeyEncipherment,DigitalSignature";
        powerShell.AddScript(gatewayAuthorityScript);

        // Export new certificate public key as a CRT file
        var myGatewayCrtPath = Path.Combine(saveDir, "MyGatewayAuthority.crt");
        var exportCrtScript =
            $"$gatewayCertPath = 'cert:\\localMachine\\my\\' + $gatewayCert.thumbprint;" +
            $"Export-Certificate" +
            $" -Cert $gatewayCertPath" +
            $" -FilePath {myGatewayCrtPath}";
        powerShell.AddScript(exportCrtScript);

        // Export the new certificate as a PFX file
        var myGatewayPfxPath = Path.Combine(saveDir, "MyGatewayAuthority.pfx");
        var exportPfxScript =
            $"Export-PfxCertificate" +
            $" -Cert $gatewayCertPath" +
            $" -FilePath {myGatewayPfxPath}" +
            $" -Password $pwd"; // Use the previous password
        powerShell.AddScript(exportPfxScript);

        powerShell.Invoke();
    }
}

Требуется PowerShell 4 или выше.

Ответ 5

@jpaugh: На самом деле это вопрос о вашем ответе. В ваших подробных шагах 3, 4, 5 вы упоминаете "локальный компьютер" и "целевой компьютер". Они оба одинаковые или разные машины? Я пытаюсь создать рабочий пример, имея клиентскую машину и сервер (слушатель). Все ваши шаги 3, 4, 5 выполнены на сервере? Спасибо!

Ответ 6

Вот полный рабочий код для HTTPListener на HTTPS (также работает в локальной сети). Чтобы создать самоподписанный сертификат в С# с помощью Bouncy Castle и разрешить доступ к URL-адресу в локальной сети.

ПРИМЕЧАНИЕ. Не забудьте запустить с правами администратора.

Шаг 1. Установите Bouncy Castle Pacakge:

Install-Package BouncyCastle -Version 1.8.5

Шаг 2. Чтобы получить доступ к URL-адресу по локальной сети, нам нужно добавить правило брандмауэра с помощью Power Shell. Добавьте ссылку на System.Management.Automation.dll. Можно найти в GAC.

Шаг 3. Полный код

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.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HTTPSListenerCode
{
    class Program
    {

        static int _sslPort;
        static Thread _serverThread;
        static HttpListener _listener;

        static void Main()
        {

            _sslPort = 34443;

            string certificateSubjectName = "MyCertificate";
            var cert = CreateInstallCert(_sslPort, certificateSubjectName, GetLocalIPAddress(), "*.domain.com");
            InitializeHTTPListner();

            string url = "https://localhost:" + _sslPort.ToString();
            System.Diagnostics.Process.Start(url);

        }


        static void InitializeHTTPListner()
        {
            //Need to Firewall rule to access the IP in LAN
            //Add refernce to C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
            var powershell = PowerShell.Create();
            var psCommand = $"New-NetFirewallRule -DisplayName \"My HTTP Listener Print Server\" -Direction Inbound -LocalPort {_sslPort} -Protocol TCP -Action Allow";
            powershell.Commands.AddScript(psCommand);
            powershell.Invoke();
            _serverThread = new Thread(HTTPListen);
            _serverThread.Start();
        }

        static void HTTPListen()
        {
            _listener = new HttpListener();
            _listener.Prefixes.Add("https://*:" + _sslPort.ToString() + "/");
            _listener.Start();

            while (true)
            {
                try
                {
                    IAsyncResult result = _listener.BeginGetContext(new AsyncCallback(HttpListenerCallback), _listener);
                    Console.WriteLine("Waiting for request to be processed asyncronously.");
                    result.AsyncWaitHandle.WaitOne(); //just needed to don't close this thread, you can do other work or run in a loop
                    Console.WriteLine("Request processed asyncronously.");

                    //HttpListenerContext context = _listener.GetContext();
                    //Process(context);
                }
                catch (Exception ex)
                {

                }
            }
        }

        static void HttpListenerCallback(IAsyncResult result)
        {
            HttpListener listener = (HttpListener)result.AsyncState;
            HttpListenerContext context = listener.EndGetContext(result);

            //Process(context);

            var html = $"<html><body><h1>HTTP Listener is working</h1></body></html>";

            byte[] bOutput2 = System.Text.Encoding.UTF8.GetBytes(html);

            context.Response.ContentType = "text/html";
            context.Response.ContentLength64 = bOutput2.Length;
            Stream OutputStream2 = context.Response.OutputStream;
            OutputStream2.Write(bOutput2, 0, bOutput2.Length);
            OutputStream2.Close();
            context.Response.StatusCode = (int)HttpStatusCode.OK;


        }

        static X509Certificate2 CreateInstallCert(int sslPort, string subjectName, string ipAddress, string domain)
        {
            X509Certificate2 cert = CheckAndGenerate(subjectName, ipAddress, domain);

            if (cert == null)
            {
                throw new ArgumentNullException("Certificate");
            }

            var applicationId = ((GuidAttribute)typeof(Program).Assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;

            var sslCert = ExecuteCommand("netsh http show sslcert 0.0.0.0:" + sslPort);
            if (sslCert.IndexOf(cert.Thumbprint, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                if (sslCert.IndexOf(applicationId, StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    return cert;
                }
            }

            Console.WriteLine(ExecuteCommand("netsh http delete sslcert ipport=0.0.0.0:" + sslPort));
            sslCert = ExecuteCommand("netsh http show sslcert 0.0.0.0:" + sslPort);
            Console.WriteLine(sslCert);

            if (sslCert.IndexOf(applicationId, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                Console.WriteLine("This implies we can start running.");
                Console.WriteLine(ExecuteCommand("netsh http delete sslcert ipport=0.0.0.0:" + sslPort));
            }

            Console.WriteLine(ExecuteCommand($"netsh http add sslcert ipport=0.0.0.0:{sslPort} certhash={cert.Thumbprint} appid={{{applicationId}}}"));

            return cert;
        }

        static X509Certificate2 CheckAndGenerate(string subjectName, string ipAddress, string domain)
        {
            AsymmetricKeyParameter caPrivateKey = null;

            string subjectCAName = subjectName + "CA";

            var caCert = CheckIfCertificateExists(subjectCAName, StoreName.Root, StoreLocation.LocalMachine);
            var clientCert = CheckIfCertificateExists(subjectName, StoreName.My, StoreLocation.LocalMachine);

            if (caCert == null)
            {

                caCert = GenerateCACertificate("CN=" + subjectCAName, ref caPrivateKey);
                addCertToStore(caCert, StoreName.Root, StoreLocation.LocalMachine);
                if (clientCert == null)
                {
                    clientCert = GenerateSelfSignedCertificate("CN=" + subjectName, "CN=" + subjectCAName, caPrivateKey, ipAddress, domain);
                    var p12 = clientCert.Export(X509ContentType.Pfx);
                    addCertToStore(new X509Certificate2(p12, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), StoreName.My, StoreLocation.LocalMachine);
                    addCertToStore(new X509Certificate2(p12, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), StoreName.Root, StoreLocation.LocalMachine);
                }

            }

            return clientCert;
        }


        static X509Certificate2 CheckIfCertificateExists(string subjectName, StoreName storeName, StoreLocation storeLocation)
        {
            X509Store store = new X509Store(storeName, storeLocation);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2 certificate = null;

            try
            {
                var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false);
                if (certificates != null && certificates.Count > 0)
                {
                    ///log.Info("CHECK for X509 Certificate in localmachine certificate store = OK");
                    certificate = certificates[0];
                }

            }
            catch (Exception ex)
            {

            }
            return certificate;

        }



        static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey, string ipAddress, string domain)
        {
            const int keyStrength = 2048;

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            certificateGenerator.SetSerialNumber(serialNumber);

            // Signature Algorithm
            const string signatureAlgorithm = "SHA256WithRSA";
            certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

            // Issuer and Subject Name
            X509Name subjectDN = new X509Name(subjectName);
            X509Name issuerDN = new X509Name(issuerName);
            certificateGenerator.SetIssuerDN(issuerDN);
            certificateGenerator.SetSubjectDN(subjectDN);

            // Valid For
            DateTime notBefore = DateTime.UtcNow.Date;
            DateTime notAfter = notBefore.AddYears(2);

            certificateGenerator.SetNotBefore(notBefore);
            certificateGenerator.SetNotAfter(notAfter);

            // 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
            AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;

            //
            List<GeneralName> altNames = new List<GeneralName>();
            altNames.Add(new GeneralName(GeneralName.IPAddress, "127.0.0.1"));
            altNames.Add(new GeneralName(GeneralName.IPAddress, ipAddress));
            altNames.Add(new GeneralName(GeneralName.DnsName, domain));
            altNames.Add(new GeneralName(GeneralName.DnsName, "localhost"));

            GeneralNames subjectAltNames = GeneralNames.GetInstance(new DerSequence((GeneralName[])altNames.ToArray()));
            certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, subjectAltNames);
            //

            // selfsign certificate
            Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerPrivKey, random);


            // correcponding private key
            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);


            // merge into X509Certificate2
            X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

            Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
            if (seq.Count != 9)
            {
                //throw new PemException("malformed sequence in RSA private key");
            }

            RsaPrivateKeyStructure 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 = ToDotNetKey(rsaparams); //x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
            return x509;

        }

        static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
        {
            var cspParams = new CspParameters
            {
                KeyContainerName = Guid.NewGuid().ToString(),
                KeyNumber = (int)KeyNumber.Exchange,
                Flags = CspProviderFlags.UseMachineKeyStore
            };

            var rsaProvider = new RSACryptoServiceProvider(cspParams);
            var parameters = new RSAParameters
            {
                Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
                P = privateKey.P.ToByteArrayUnsigned(),
                Q = privateKey.Q.ToByteArrayUnsigned(),
                DP = privateKey.DP.ToByteArrayUnsigned(),
                DQ = privateKey.DQ.ToByteArrayUnsigned(),
                InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
                D = privateKey.Exponent.ToByteArrayUnsigned(),
                Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
            };

            rsaProvider.ImportParameters(parameters);
            return rsaProvider;
        }

        static X509Certificate2 GenerateCACertificate(string subjectName, ref AsymmetricKeyParameter CaPrivateKey)
        {
            const int keyStrength = 2048;

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            certificateGenerator.SetSerialNumber(serialNumber);

            // Signature Algorithm
            const string signatureAlgorithm = "SHA256WithRSA";
            certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);

            // Issuer and Subject Name
            X509Name subjectDN = new X509Name(subjectName);
            X509Name issuerDN = subjectDN;
            certificateGenerator.SetIssuerDN(issuerDN);
            certificateGenerator.SetSubjectDN(subjectDN);

            // Valid For
            DateTime notBefore = DateTime.UtcNow.Date;
            DateTime notAfter = notBefore.AddYears(2);

            certificateGenerator.SetNotBefore(notBefore);
            certificateGenerator.SetNotAfter(notAfter);

            // Subject Public Key
            AsymmetricCipherKeyPair subjectKeyPair;
            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
            RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);
            subjectKeyPair = keyPairGenerator.GenerateKeyPair();

            certificateGenerator.SetPublicKey(subjectKeyPair.Public);

            // Generating the Certificate
            AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;

            // selfsign certificate
            Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
            X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

            CaPrivateKey = issuerKeyPair.Private;

            return x509;
            //return issuerKeyPair.Private;

        }

        static bool addCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
        {
            bool bRet = false;

            try
            {
                X509Store store = new X509Store(st, sl);
                store.Open(OpenFlags.ReadWrite);
                store.Add(cert);

                store.Close();
            }
            catch
            {

            }

            return bRet;
        }

        static string GetLocalIPAddress()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    return ip.ToString();
                }
            }
            return "127.0.0.1";
            //throw new Exception("No network adapters with an IPv4 address in the system!");
        }

        static string ExecuteCommand(string action)
        {
            StringBuilder stringBuilder = new StringBuilder();
            using (Process process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    WindowStyle = ProcessWindowStyle.Normal,
                    FileName = "cmd.exe",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    Arguments = "/c " + action
                }
            })
            {
                Console.WriteLine("Executing Command:");
                Console.WriteLine(action);
                process.Start();
                while (!process.StandardOutput.EndOfStream)
                {
                    stringBuilder.AppendLine(process.StandardOutput.ReadLine());
                }
                process.Close();
            }

            return stringBuilder.ToString();
        }
    }
}