개발인증서 생성과 자동 설치 및 포트 바인딩
* 모두삭제
del hostname.*
* private key 와 인증서 및 인증서 암호를 입력한다.
makecert -r -len 2048 -pe -n "CN=HOSTNAME" -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4 -sky exchange -sv HOSTNAME.pvk HOSTNAME.cer -b 01/01/2005 -e 01/01/2035
* 암호입력
1234
* 포터블 파일로 변경한다.
pvk2pfx -pvk HOSTNAME.pvk -spc HOSTNAME.cer -pfx HOSTNAME.pfx -pi 1234 -po 1234 -f
* pfx my, localhost 에 등록
* cer Root, localhost 에 등록
* certlm.mmc 에서 Personal + Trusted Root Certi 저장소에 HOSTNAME pfx 와 cert 파일이 있는지 확인한다.
* 자동으로 등록하는 클래스 Certification.cs 확인
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using CsLib;
namespace WcfHttpsServer
{
class Certification
{
public bool Bind(string path, string pfx, string pfxpassword, string cert, string port)
{
try
{
string pfxFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path, pfx);
string certFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path, cert);
DeleteCertification(pfxFileName
, StoreName.My
, StoreLocation.LocalMachine
, pfxpassword
, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
DeleteCertification(certFileName
, StoreName.Root
, StoreLocation.LocalMachine);
InstallCertification(pfxFileName
, StoreName.My
, StoreLocation.LocalMachine
, pfxpassword
, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
InstallCertification(certFileName
, StoreName.Root
, StoreLocation.LocalMachine);
CertificationNetBind(certFileName, port);
}
catch (Exception)
{
throw;
}
return true;
}
private void InstallCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion, string password, X509KeyStorageFlags x509KeyStorageFlags)
{
X509Store store = new X509Store(storeName, storeLocaion);
try
{
bool Exists = false;
X509Certificate2 cert = new X509Certificate2(certFileName, TranString.convertToSecureString(password), x509KeyStorageFlags);
store.Open(OpenFlags.ReadWrite);
foreach (X509Certificate2 storeCert in store.Certificates)
{
if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
{
Exists = true;
break;
}
}
if (!Exists)
{
store.Add(cert);
}
}
catch (Exception)
{
throw;
}
finally
{
store.Close();
}
}
private void InstallCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion)
{
X509Store store = new X509Store(storeName, storeLocaion);
try
{
bool Exists = false;
X509Certificate2 cert = new X509Certificate2(certFileName);
store.Open(OpenFlags.ReadWrite);
foreach (X509Certificate2 storeCert in store.Certificates)
{
if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
{
Exists = true;
break;
}
}
if (!Exists)
{
store.Add(cert);
}
}
catch (Exception)
{
throw;
}
finally
{
store.Close();
}
}
private void DeleteCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion, string password, X509KeyStorageFlags x509KeyStorageFlags)
{
X509Store store = new X509Store(storeName, storeLocaion);
try
{
X509Certificate2 cert = new X509Certificate2(certFileName, TranString.convertToSecureString(password), x509KeyStorageFlags);
store.Open(OpenFlags.ReadWrite);
foreach (X509Certificate2 storeCert in store.Certificates)
{
if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
{
store.Remove(cert);
break;
}
}
}
catch (Exception)
{
throw;
}
finally
{
store.Close();
}
}
private void DeleteCertification(string certFile, StoreName storeName, StoreLocation storeLocaion)
{
X509Store store = new X509Store(storeName, storeLocaion);
try
{
X509Certificate2 cert = new X509Certificate2(certFile);
store.Open(OpenFlags.ReadWrite);
foreach (X509Certificate2 storeCert in store.Certificates)
{
if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
{
store.Remove(cert);
break;
}
}
}
catch (Exception)
{
throw;
}
finally
{
store.Close();
}
}
private string GetCertHash(string certFileName)
{
using (X509Certificate2 cert = new X509Certificate2(certFileName))
return cert.Thumbprint.ToLower();
}
private string GetAssemblyGuid()
{
var assembly = typeof(Program).Assembly;
var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
var id = attribute.Value;
return id.ToLower();
}
private bool CertificationNetBind(string certFileName, string port)
{
StringBuilder sbPsiResults = new StringBuilder();
ProcessStartInfo psi = new ProcessStartInfo() { CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true };
bool isBounded = false;
// SHOW
psi.FileName = "netsh";
psi.Arguments = $"http show sslcert ipport=0.0.0.0:{port}";
sbPsiResults.Clear();
Process procHttpShow = Process.Start(psi);
while (procHttpShow != null && !procHttpShow.StandardOutput.EndOfStream)
sbPsiResults.Append(procHttpShow.StandardOutput.ReadLine());
procHttpShow?.WaitForExit(2000);
if (sbPsiResults.ToString().ToLower().Contains(GetCertHash(certFileName)) && sbPsiResults.ToString().ToLower().Contains(GetAssemblyGuid()))
{
// DELETE
psi.FileName = "netsh";
psi.Arguments = $"http delete sslcert ipport=0.0.0.0:{port}";
sbPsiResults.Clear();
Process procHttpDelete = Process.Start(psi);
while (procHttpDelete != null && !procHttpDelete.StandardOutput.EndOfStream)
sbPsiResults.Append(procHttpDelete.StandardOutput.ReadLine());
procHttpDelete?.WaitForExit(2000);
if (sbPsiResults.ToString().ToLower().Contains("success"))
isBounded = false;
else
throw new Exception($"http delete sslcert error : {sbPsiResults.ToString()}");
}
else
isBounded = false;
if (!isBounded)
{
// ADD
psi.FileName = "netsh";
psi.Arguments = $"http add sslcert ipport=0.0.0.0:{port} certhash={GetCertHash(certFileName).ToLower()} appid={{{GetAssemblyGuid()}}}";
sbPsiResults.Clear();
Process procHttpAdd = Process.Start(psi);
while (procHttpAdd != null && !procHttpAdd.StandardOutput.EndOfStream)
sbPsiResults.Append(procHttpAdd.StandardOutput.ReadLine());
procHttpAdd?.WaitForExit(2000);
if (sbPsiResults.ToString().ToLower().Contains("error"))
{
isBounded = false;
throw new Exception($"http add sslcert error : {sbPsiResults.ToString()}");
}
else
isBounded = true;
}
return isBounded;
}
}
}