첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

■ X.509 인증서 만들기

------------------------------------------------------------------------------------------------------------------------

 


TestProject.zip


Program.cs

 

 

using System;

using System.Collections.Generic;

using System.Security.Cryptography.X509Certificates;

 

namespace TestProject

{

    /// <summary>

    /// 프로그램

    /// </summary>

    class Program

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 프로그램 시작하기 - Main()

 

        /// <summary>

        /// 프로그램 시작하기

        /// </summary>

        private static void Main()

        {

            bool result = NetworkHelper.DeletePortBinding(443);

 

            Console.WriteLine("포트 바인딩 삭제 결과 : " + result);

 

            CertificateKeyPair rootCertificateKeyPair;

 

            DateTime fromDate = DateTime.Now.AddDays(-1);

            DateTime toDate   = fromDate.AddYears(1);

 

            X509Certificate2 rootCertificate = CertificateHelper.CreateRootCertificate

            (

                "CN=TestRootCA",

                fromDate,

                toDate,

                out rootCertificateKeyPair

            );

 

            List<string> sanList = new List<string>();

 

            sanList.Add("github.com");

 

            X509Certificate2 certificate = CertificateHelper.CreateCertificate

            (

                rootCertificate,

                rootCertificateKeyPair,

                "CN=Test",

                fromDate,

                toDate,

                sanList

            );

 

            CertificateHelper.Store(rootCertificate, StoreName.AuthRoot, StoreLocation.LocalMachine);

 

            CertificateHelper.Store(certificate, StoreName.My, StoreLocation.CurrentUser);

 

            result = NetworkHelper.BindToPort(certificate, 443, "A613FCA4-51D2-4C33-8377-362BB6D54A00");

 

            Console.WriteLine("포트 바인딩 결과 : " + result);

 

            result = NetworkHelper.FlushDNS();

 

            Console.WriteLine("DNS 플러시 결과 : " + result);

 

            CertificateHelper.SaveToCer(certificate, "d:\\test.cer");

            CertificateHelper.SaveToPfx(certificate, "d:\\test.pfx");

        }

 

        #endregion

    }

}

 

 

NetworkHelper.cs

 

 

using System.Diagnostics;

using System.Security.Cryptography.X509Certificates;

 

namespace TestProject

{

    /// <summary>

    /// 네트워크 헬퍼

    /// </summary>

    public static class NetworkHelper

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 포트 바인딩하기 - BindToPort(x509Certificate2, port, applicationID)

 

        /// <summary>

        /// 포트 바인딩하기

        /// </summary>

        /// <param name="x509Certificate2">X.509 인증서 2</param>

        /// <param name="port">포트</param>

        /// <param name="applicationID">애플리케이션 ID</param>

        /// <returns>처리 결과</returns>

        public static bool BindToPort(X509Certificate2 x509Certificate2, int port, string applicationID)

        {

            string command = string.Format

            (

                "http add sslcert ipport=0.0.0.0:{0} certhash={1} appid={{{2}}}",

                port,

                x509Certificate2.Thumbprint,

                applicationID

            );

 

            Process process = new Process();

 

            process.StartInfo.FileName    = "netsh.exe";

            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            process.StartInfo.Arguments   = command;

 

            process.Start();

 

            process.WaitForExit();

 

            return process.ExitCode == 0;

        }

 

        #endregion

        #region 포트 바인딩 삭제하기 - DeletePortBinding(port)

 

        /// <summary>

        /// 포트 바인딩 삭제하기

        /// </summary>

        /// <param name="port">포트</param>

        /// <returns>처리 결과</returns>

        public static bool DeletePortBinding(int port)

        {

            string command = string.Format("http delete sslcert ipport=0.0.0.0:{0}", port);

 

            Process process = new Process();

 

            process.StartInfo.FileName    = "netsh.exe";

            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            process.StartInfo.Arguments   = command;

 

            process.Start();

 

            process.WaitForExit();

 

            return process.ExitCode == 0;

        }

 

        #endregion

        #region DNS 캐시 지우기 - FlushDNS()

 

        /// <summary>

        /// DNS 캐시 지우기

        /// </summary>

        /// <returns>처리 결과</returns>

        public static bool FlushDNS()

        {

            string command = string.Format("/flushdns");

 

            Process process = new Process();

 

            process.StartInfo.FileName    = "ipconfig.exe";

            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            process.StartInfo.Arguments   = command;

 

            process.Start();

 

            process.WaitForExit();

 

            return process.ExitCode == 0;

        }

 

        #endregion

    }

}

 

 

CertificateKeyPair.cs

 

 

using Org.BouncyCastle.Crypto;

 

namespace TestProject

{

    /// <summary>

    /// 인증서 키 쌍

    /// </summary>

    public class CertificateKeyPair

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 비대칭 암호화 키 쌍

        /// </summary>

        private AsymmetricCipherKeyPair asymmetricCipherKeyPair;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 개인 키 - PrivateKey

 

        /// <summary>

        /// 개인 키

        /// </summary>

        public AsymmetricKeyParameter PrivateKey

        {

            get

            {

                return this.asymmetricCipherKeyPair.Private;

            }

        }

 

        #endregion

        #region 공개 키 - PublicKey

 

        /// <summary>

        /// 공개 키

        /// </summary>

        public AsymmetricKeyParameter PublicKey

        {

            get

            {

                return this.asymmetricCipherKeyPair.Public;

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - CertificateKeyPair(asymmetricCipherKeyPair)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="asymmetricCipherKeyPair">비대칭 암호화 키 쌍</param>

        public CertificateKeyPair(AsymmetricCipherKeyPair asymmetricCipherKeyPair)

        {

            this.asymmetricCipherKeyPair = asymmetricCipherKeyPair;

        }

 

        #endregion

    }

}

 

 

CertificateHelper.cs

 

 

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Security.Cryptography;

using System.Security.Cryptography.X509Certificates;

 

using Org.BouncyCastle.Asn1.X509;

using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Generators;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Math;

using Org.BouncyCastle.Security;

using Org.BouncyCastle.X509;

using Org.BouncyCastle.X509.Extension;

using Org.BouncyCastle.Asn1;

 

using X509Certificate = Org.BouncyCastle.X509.X509Certificate;

 

namespace TestProject

{

    /// <summary>

    /// 인증서 헬퍼

    /// </summary>

    public class CertificateHelper

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 루트 인증서 생성하기 - CreateRootCertificate(domainName, fromDate, toDate, certificateKeyPair, keySize)

 

        /// <summary>

        /// 루트 인증서 생성하기

        /// </summary>

        /// <param name="domainName">도메인명</param>

        /// <param name="fromDate">FROM 날짜</param>

        /// <param name="toDate">TO 날짜</param>

        /// <param name="certificateKeyPair">인증서 키 쌍</param>

        /// <param name="keySize">키 크기</param>

        /// <returns>X.509 인증서 2</returns>

        public static X509Certificate2 CreateRootCertificate

        (

            string                 domainName,

            DateTime               fromDate,

            DateTime               toDate,

            out CertificateKeyPair certificateKeyPair,

            int                    keySize = 1024

        )

        {

            RsaKeyPairGenerator rsaKeyPairGenerator = new RsaKeyPairGenerator();

 

            rsaKeyPairGenerator.Init(new KeyGenerationParameters(new SecureRandom(), keySize));

 

            AsymmetricCipherKeyPair cipherKeyPair = rsaKeyPairGenerator.GenerateKeyPair();

 

            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

 

            certificateGenerator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));

            certificateGenerator.SetIssuerDN(new X509Name(domainName));

            certificateGenerator.SetNotBefore(fromDate);

            certificateGenerator.SetNotAfter(toDate);

            certificateGenerator.SetSubjectDN(new X509Name(domainName));

            certificateGenerator.SetPublicKey(cipherKeyPair.Public);

            certificateGenerator.SetSignatureAlgorithm("SHA1WithRSAEncryption");

 

            X509Certificate certificate = certificateGenerator.Generate

            (

                cipherKeyPair.Private,

                new SecureRandom()

            );

 

            certificate.Verify(cipherKeyPair.Public);

 

            certificateKeyPair = new CertificateKeyPair(cipherKeyPair);

 

            return new X509Certificate2(DotNetUtilities.ToX509Certificate(certificate));

        }

 

        #endregion

        #region 인증서 생성하기 - CreateCertificate(rootCertificate, certificateKeyPair, domainName, fromDate, toDate, sanEnumerable, keySize)

 

        /// <summary>

        /// 인증서 생성하기

        /// </summary>

        /// <param name="rootCertificate">루트 인증서</param>

        /// <param name="certificateKeyPair">인증서 키 쌍</param>

        /// <param name="domainName">도메인명</param>

        /// <param name="fromDate">FROM 날짜</param>

        /// <param name="toDate">TO 날짜</param>

        /// <param name="sanEnumerable">Subject Alternative Name 열거 가능형</param>

        /// <param name="keySize">키 크기</param>

        /// <returns>X.509 인증서 2</returns>

        public static X509Certificate2 CreateCertificate

        (

            X509Certificate2    rootCertificate,

            CertificateKeyPair  certificateKeyPair,

            string              domainName,

            DateTime            fromDate,

            DateTime            toDate,

            IEnumerable<string> sanEnumerable,

            int                 keySize = 1024

        )

        {

            new RsaKeyPairGenerator().Init(new KeyGenerationParameters(new SecureRandom(), keySize));

 

            RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();

 

            keyPairGenerator.Init(new KeyGenerationParameters(new SecureRandom(), keySize));

 

            AsymmetricCipherKeyPair cipherKeyPair = keyPairGenerator.GenerateKeyPair();

 

            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

 

            certificateGenerator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));

            certificateGenerator.SetSubjectDN(new X509Name(domainName));

            certificateGenerator.SetIssuerDN(new X509Name(rootCertificate.SubjectName.Name));

            certificateGenerator.SetNotBefore(fromDate);

            certificateGenerator.SetNotAfter(toDate);

            certificateGenerator.SetPublicKey(cipherKeyPair.Public);

            certificateGenerator.SetSignatureAlgorithm("SHA1WithRSAEncryption");

 

            Asn1Encodable[] asn1EncodableArray = sanEnumerable.Select

            (

                name => (Asn1Encodable)new GeneralName(GeneralName.DnsName, name)

            ).ToArray();

 

            DerSequence derSequence = new DerSequence(asn1EncodableArray);

 

            certificateGenerator.AddExtension

            (

                X509Extensions.SubjectAlternativeName,

                false,

                derSequence

            );

 

            certificateGenerator.AddExtension

            (

                X509Extensions.AuthorityKeyIdentifier,

                false,

                new AuthorityKeyIdentifierStructure(DotNetUtilities.FromX509Certificate(rootCertificate))

            );

 

            certificateGenerator.AddExtension

            (

                X509Extensions.SubjectKeyIdentifier,

                false,

                new SubjectKeyIdentifierStructure(cipherKeyPair.Public)

            );

 

            X509Certificate certificate = certificateGenerator.Generate(certificateKeyPair.PrivateKey);

 

            certificate.Verify(certificateKeyPair.PublicKey);

 

            AsymmetricAlgorithm privateKey = GetPrivateKey((RsaPrivateCrtKeyParameters)cipherKeyPair.Private);

 

            X509Certificate2 certificate2 = new X509Certificate2(DotNetUtilities.ToX509Certificate(certificate));

 

            certificate2.PrivateKey = privateKey;

 

            return certificate2;

        }

 

        #endregion

        #region .cer 파일 저장하기 - SaveToCer(certificate, filePath)

 

        /// <summary>

        /// .cer 파일 저장하기

        /// </summary>

        /// <param name="certificate">인증서</param>

        /// <param name="filePath">파일 경로</param>

        public static void SaveToCer(X509Certificate2 certificate, string filePath)

        {

            byte[] byteArray = certificate.Export(X509ContentType.Cert);

 

            File.WriteAllBytes(filePath, byteArray);

        }

 

        #endregion

        #region .pfx 파일 저장하기 - SaveToPfx(certificate, filePath, password)

 

        /// <summary>

        /// .pfx 파일 저장하기

        /// </summary>

        /// <param name="certificate">인증서</param>

        /// <param name="filePath">파일 경로</param>

        /// <param name="password">패스워드</param>

        public static void SaveToPfx(X509Certificate2 certificate, string filePath, string password = null)

        {

            byte[] byteArray = certificate.Export(X509ContentType.Pfx, password);

 

            File.WriteAllBytes(filePath, byteArray);

        }

 

        #endregion

        #region 저장하기 - Store(certificate, storeName, storeLocation)

 

        /// <summary>

        /// 저장하기

        /// </summary>

        /// <param name="certificate">인증서</param>

        /// <param name="storeName">저장소명</param>

        /// <param name="storeLocation">저장 위치</param>

        public static void Store(X509Certificate2 certificate, StoreName storeName, StoreLocation storeLocation)

        {

            X509Store store = new X509Store(storeName, storeLocation);

 

            store.Open(OpenFlags.ReadWrite);

 

            store.Add(certificate);

 

            store.Close();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 개인 키 구하기 - GetPrivateKey(rsaPrivateCrtKeyParameters)

 

        /// <summary>

        /// 개인 키 구하기

        /// </summary>

        /// <param name="rsaPrivateCrtKeyParameters">RSA 개인 인증서 키 매개 변수</param>

        /// <returns>개인 키</returns>

        private static AsymmetricAlgorithm GetPrivateKey(RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters)

        {

            CspParameters cspParameters = new CspParameters

            {

                KeyContainerName = Guid.NewGuid().ToString(),

                KeyNumber        = (int)KeyNumber.Exchange,

                Flags            = CspProviderFlags.UseMachineKeyStore

            };

 

            RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(cspParameters);

 

            RSAParameters rsaParameters = new RSAParameters

            {

                Modulus  = rsaPrivateCrtKeyParameters.Modulus.ToByteArrayUnsigned(),

                P        = rsaPrivateCrtKeyParameters.P.ToByteArrayUnsigned(),

                Q        = rsaPrivateCrtKeyParameters.Q.ToByteArrayUnsigned(),

                DP       = rsaPrivateCrtKeyParameters.DP.ToByteArrayUnsigned(),

                DQ       = rsaPrivateCrtKeyParameters.DQ.ToByteArrayUnsigned(),

                InverseQ = rsaPrivateCrtKeyParameters.QInv.ToByteArrayUnsigned(),

                D        = rsaPrivateCrtKeyParameters.Exponent.ToByteArrayUnsigned(),

                Exponent = rsaPrivateCrtKeyParameters.PublicExponent.ToByteArrayUnsigned()

            };

 

            rsaCryptoServiceProvider.ImportParameters(rsaParameters);

 

            return rsaCryptoServiceProvider;

        }

 

        #endregion

    }

}

 

------------------------------------------------------------------------------------------------------------------------

※ 관리자 모드에서 실행해야 한다.

※ 패키지 설치 : BouncyCastle

 

1. 비주얼 스튜디오를 실행한다.

2. 비주얼 스튜디오에서 [도구] / [NuGet 패키지 관리자] / [패키지 관리자 콘솔] 메뉴를 클릭한다.

3. [패키지 관리자 콘솔]에서 아래 명령을 실행한다.

 

 

Install-Package BouncyCastle

 

 

728x90
반응형
Posted by 사용자 icodebroker

댓글을 달아 주세요