Nice programing

HTTPS를 지원하는 Httplistener

nicepro 2020. 12. 11. 19:26
반응형

HTTPS를 지원하는 Httplistener


.NET HTTPListener HTTPS를 지원하는 것과 관련하여 혼란스럽고 때로는 충돌하는 정보가 많이있는 것 같습니다. 내 이해는 다음과 같습니다.

  • 수신기가이 포트에서 SSL 요청을 처리해야한다는 것을 이해하려면 C # 코드에 https접두사 (예 https://*:8443:)가 필요합니다.

  • 실제 SSL 핸드 셰이크는 내부적으로 발생 http.sys하며 Windows 시스템 어딘가에 묻혀 있습니다. C # 코드는 SSL 핸드 셰이크를 내부에서 발생하므로 명시 적으로 관리 할 필요가 없습니다.

  • 하나는 httpListener컴퓨터 에 "X.509 신뢰할 수있는 인증서"가 있어야 하고 어떻게 든 해당 인증서를 포트 8443 (이 예에서)에 바인딩해야합니다.

위의 이해가 맞습니까? 그렇지 않다면 저를 교육하십시오.

X.509 인증서와 관련하여 내 이해는 다음과 같습니다.

  • makecertX.509 인증서를 만드는 데 사용 합니다. 이 인증서는 개인 저장소에 저장되고 신뢰할 수있는 저장소 (HTTP 리스너가 표시되는 위치)로 이동해야합니다. 내가 사용할 수있는 것 같다 certMgr이동을 수행하기 위해, 또는 내가 사용할 수있는 mmc이동에 영향을 할 수 있습니다. 그것은 하나 이상의 X.509 인증서 형식이 (것 같다 DER, Base64, pks,, 보호 PSWD pks내가 사용해야 원하는 형식이 있는가 ..., 개인 등.)?

인증서를 신뢰할 수있는 저장소로 가져 오면이를 TCP 포트에 바인딩해야합니다. 나는 윈도우 7에 오전 : 나는 사용해야 httpcfgnetsh?


나는 많은 숙제를했고이 일을 해냈다. .NET HttpListener에 대한 SSL 지원을 추가하는 단계는 다음과 같습니다.

  1. https접두사 를 포함하도록 C # 애플리케이션 코드를 업데이트 합니다. 예:

    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.exeSSL 인증서를 만드는 데 사용

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

    • MMC GUI를 사용하여 Trusted Authority 저장소에 CA 설치

    • 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 값을 찾습니다.

위의 작업을 수행하는 다른 방법이있을 수 있지만 이것은 저에게 효과적이었습니다.


다음은 OpenSSL을 사용하여 C # HTTPListener애플리케이션에 대한 자체 서명 된 인증서를 생성하여 Windows에서 독립 실행 형 서버를 설정하기 위해 수행 한 단계 입니다. 추가 조사를 원할 경우를 위해 많은 링크가 포함되어 있습니다.

  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은 Walter의 답변을 참조하십시오 .

  3. 로컬 컴퓨터 용 인증서 관리자를 엽니 다. 를 실행 certmgr.msc하면 현재 사용자에 대한 인증서 관리자 가 열리지 만 여기서 원하는 것은 아닙니다. 대신 :

    1. 대상 머신의 관리 명령 프롬프트에서 다음을 실행하십시오. mmc
    2. 를 누르 거나 클릭Ctrl + MFile > 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 바인딩 * 및 적절한 포트를 설정합니다. NB : 이 명령은 (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. 웹 서버를 시작하십시오.


답변에서 자체 서명 된 인증서를 만드는 것이 저에게 효과가 없었고 질문이 구체적으로 .net HTTPListener https를 사용할 수 있도록 만들고 팁 / 조언을 요청함에 따라 제 접근 방식을 공유하고 싶습니다. www.made-up.com과 같이 WAN IP를 가리키고 (예 : 호스트 공급자에게 지침 요청) 해당 포트 (예 : 443)를 로컬 컴퓨터로 전달해야합니다. 방화벽에서 해당 인바운드 443 포트를 여는 것을 잊지 마십시오. 로컬 컴퓨터.

https://letsencrypt.org/ 사용했습니다 . Windows 용 공식 certbot ACME 클라이언트가 없기 때문에 Windows에서는 Linux처럼 쉽지 않습니다. 그러나 https://github.com/Lone-Coder/letsencrypt-win-simple 을 사용할 수 있으며이 중 바이너리도 있습니다. 그러나 "현재 IIS 만 지원됩니다". 그러나 SSL 방식으로 httplistener에 접근 할 수 있도록 컴퓨터에 인증서를 생성하도록 쉽게 속일 수 있습니다.

  1. Windows 기능을 통해 IIS를 설치하고 IIS 내에 웹 사이트를 만들고 호스트 이름을 할당합니다. 또한 보안 (443 포트) 웹 사이트를 만드십시오.
  2. letsencrypt-win-simple exe를 실행합니다 (버전 1.9.1 사용). 인증서를 생성 할 수 있도록 질문에 답하십시오.
  3. 그 후에 IIS 서버를 중지 할 수 있습니다.

생성 된 새로 고침 작업을 기록해 두어야한다고 생각합니다. 몇 달 후에 성공할지 확신 할 수 없기 때문입니다 (인증서를 갱신하려면 IIS를 다시 시작해야합니다).


PowerShell 및 C #을 사용하여 인증서를 가져올 수 있습니다 (수동 단계 필요 없음).

자세한 내용은 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 이상이 필요합니다.


다음은 HTTPS의 HTTPListener에 대한 전체 작동 코드입니다 (LAN에서도 작동 함). Bouncy Castle을 사용하여 C #에서 자체 서명 된 인증서를 생성하고 LAN에서 URL에 액세스하도록 허용합니다.

참고 : 관리자로 실행하는 것을 잊지 마십시오.

1 단계 : Bouncy Castle Pacakge 설치 :

Install-Package BouncyCastle -Version 1.8.5

2 단계 : LAN을 통해 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();
        }
    }
}

참고 URL : https://stackoverflow.com/questions/11403333/httplistener-with-https-support

반응형