|
@@ -0,0 +1,716 @@
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
+using Newtonsoft.Json;
|
|
|
+using System;
|
|
|
+using System.Diagnostics;
|
|
|
+using System.Diagnostics.Metrics;
|
|
|
+using System.Reflection;
|
|
|
+using System.Runtime.ConstrainedExecution;
|
|
|
+using System.Security.AccessControl;
|
|
|
+using System.Security.Cryptography;
|
|
|
+using System.Security.Cryptography.X509Certificates;
|
|
|
+using System.Text;
|
|
|
+using System.Xml.Linq;
|
|
|
+
|
|
|
+namespace CAUtilLib
|
|
|
+{
|
|
|
+ public partial class CaUtil
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// 建構子生成路徑可透過SetPath進行路徑覆寫
|
|
|
+ /// </summary>
|
|
|
+ public CaUtil(ILogger<CaUtil> logger)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(this.path))
|
|
|
+ {
|
|
|
+ string path = Directory.GetCurrentDirectory();
|
|
|
+ //string parentPath = Directory.GetParent(Directory.GetParent(Directory.GetParent(Directory.GetParent(path).ToString()).ToString()).ToString()) + @"\";
|
|
|
+ string filePath = Path.Combine(path, "temp");
|
|
|
+ bool exists = Directory.Exists(filePath);
|
|
|
+ if (!exists)
|
|
|
+ {
|
|
|
+ CreateFolder(filePath);
|
|
|
+ MoveFile(@"zerova_v3.cnf", filePath + @"\zerova_v3.cnf");
|
|
|
+ }
|
|
|
+ this.path = filePath;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.logger = logger;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string path = "";
|
|
|
+ private readonly ILogger<CaUtil> logger;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 檔案路徑
|
|
|
+ /// </summary>
|
|
|
+ public string SavePath
|
|
|
+ {
|
|
|
+ get => path;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ if (this.path == value)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.path = value;
|
|
|
+ string filePath = this.path;
|
|
|
+ CreateFolder(filePath);
|
|
|
+ MoveFile(@"zerova_v3.cnf", Path.Combine(filePath, @"zerova_v3.cnf"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public OSType OS { get; set; }
|
|
|
+
|
|
|
+ private string ExecuteShell => OS == OSType.Windows ? "cmd.exe" : "/bin/bash";
|
|
|
+ private string CatCmd => OS == OSType.Windows ? "type " : "cat";
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成RootCA憑證
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="name">Root CA</param>
|
|
|
+ /// <param name="Days">憑證有效期限</param>
|
|
|
+ /// <param name="SerialNumber">序號</param>
|
|
|
+ /// <param name="Cn">主機名或網站地址</param>
|
|
|
+ /// <param name="organizationName">組織名稱</param>
|
|
|
+ /// <param name="Hash">使用SHA256/SHA512演算法進行簽名</param>
|
|
|
+ /// <param name="RsaKey">生成2048位元或4096位元的私鑰</param>
|
|
|
+ /// <param name="Caformat">生成crt 或者pem 格式</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> CreateRootCA(
|
|
|
+ string name,
|
|
|
+ string commonName,
|
|
|
+ string organizationName,
|
|
|
+ string Country = "TW",
|
|
|
+ string State = "Taipei",
|
|
|
+ int Days = 3650,
|
|
|
+ string SerialNumber = "",
|
|
|
+ HashAlgorithm Hash = HashAlgorithm.SHA512,
|
|
|
+ OpensslGenrsaRsa RsaKey = OpensslGenrsaRsa.Key4096)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(SerialNumber))
|
|
|
+ {
|
|
|
+ SerialNumber = await GetOpenSSLRandSn();
|
|
|
+ }
|
|
|
+
|
|
|
+ var status = false;
|
|
|
+ var keyName = "";
|
|
|
+ keyName = name;
|
|
|
+ string sn = "0x" + SerialNumber;
|
|
|
+ HashAlgorithm ha = Hash;
|
|
|
+ var sslKey = (int)RsaKey;
|
|
|
+
|
|
|
+ var subjString = CreateSubjectString(CommonName: commonName, Organization: organizationName, Country: Country, State: State);
|
|
|
+
|
|
|
+ if (await CreateKey(keyName, RsaKey) &&
|
|
|
+ await ExecShellCmd("openssl", $"req -x509 -new -nodes -set_serial {sn} -key {keyName}.key -{ha} -days {Days} -subj \"{subjString}\" -out {name}.crt ") &&
|
|
|
+ await MergeFile($"{name}.pem", $"{name}.crt", $"{keyName}.key")
|
|
|
+ //&& await ExecShellCmd("certutil", $"-f -addstore root {RootCa}.crt ")
|
|
|
+ //&& await ExecShellCmd("certutil", $"-f -addstore root {RootCa}.crt ")
|
|
|
+ )
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ //create
|
|
|
+ string[] strs = new string[5];
|
|
|
+ strs[0] = "openssl genrsa -out " + keyName + ".key " + sslKey + " ";
|
|
|
+ strs[1] = "openssl req -x509 -new -nodes -set_serial " + sn + " -key " + keyName + ".key -" + ha + " -days " + Days + " -subj \"/C=TW/ST=Taipei/O=" + organizationName + "/OU=phihong_sub.IO/CN=" + commonName + "/emailAddress=phihong_sub@mail.com\" -out " + name + ".crt ";
|
|
|
+ strs[2] = CatCmd + name + ".crt " + keyName + ".key > " + name + ".pem ";
|
|
|
+ strs[3] = "certutil -f -addstore root " + name + ".crt ";
|
|
|
+ strs[4] = "certutil -f -addstore root " + name + ".crt ";
|
|
|
+
|
|
|
+ for (int i = 0; i < strs.Length; i++)
|
|
|
+ {
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + strs[i],
|
|
|
+ WorkingDirectory = this.path,
|
|
|
+ StandardOutputEncoding = Encoding.UTF8,
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ RedirectStandardError = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ _ = process.StandardOutput.ReadToEndAsync().ContinueWith(( t => {
|
|
|
+ logger.LogTrace(t.Result);
|
|
|
+ }));
|
|
|
+ _ = process.StandardError.ReadToEndAsync().ContinueWith((t => {
|
|
|
+ logger.LogTrace(t.Result);
|
|
|
+ }));
|
|
|
+ await process.WaitForExitAsync();
|
|
|
+ if (process.ExitCode != 0)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成SubCA子憑證
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="RootCaName">CA憑證名稱</param>
|
|
|
+ /// <param name="Days">憑證有效期限</param>
|
|
|
+ /// <param name="SubCA">子憑證名稱</param>
|
|
|
+ /// <param name="SerialNumber">序號</param>
|
|
|
+ /// <param name="commonName">主機名或網站地址</param>
|
|
|
+ /// <param name="organizationName">組織名稱</param>
|
|
|
+ /// <param name="Hash">使用SHA256/SHA512演算法進行簽名</param>
|
|
|
+ /// <param name="RsaKey">生成2048位元或4096位元的私鑰</param>
|
|
|
+ /// <param name="Caformat">生成crt 或者pem 格式</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> CreateSubCA(string RootCa, string Days,
|
|
|
+ string SubCA, string SerialNumber, string commonName, string organizationName, HashAlgorithm Hash, OpensslGenrsaRsa RsaKey, Certificateformat Caformat)
|
|
|
+ {
|
|
|
+
|
|
|
+ if (string.IsNullOrEmpty(SerialNumber))
|
|
|
+ {
|
|
|
+ SerialNumber = await GetOpenSSLRandSn();
|
|
|
+ }
|
|
|
+
|
|
|
+ var status = false;
|
|
|
+ var str = "";
|
|
|
+ string sn = "0x" + SerialNumber;
|
|
|
+ //hashAlgorithm ha = Hash;
|
|
|
+ var sslKey = (int)RsaKey;
|
|
|
+ Certificateformat format = Caformat;
|
|
|
+
|
|
|
+ if (await ExecShellCmd("openssl", $"genrsa -out {SubCA}.key {sslKey}") &&
|
|
|
+ await ExecShellCmd("openssl", $"req -new -{Hash} -nodes -key {SubCA}.key -out {SubCA}.csr -subj \"/C=TW/ST=Taipei/O={organizationName}/OU=phihong_sub.IO/CN={commonName}/emailAddress=phihong_sub@mail.com\" ") &&
|
|
|
+ await ExecShellCmd("openssl", $"x509 -set_serial {sn} -req -in {SubCA}.csr -CA {RootCa}.crt -CAkey {RootCa}.key -CAcreateserial -out {SubCA}.crt -days {Days} -sha256 -extfile zerova_v3.cnf ") &&
|
|
|
+ await MergeFile($"{SubCA}.pem", $"{SubCA}.crt", $"{SubCA}.key"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+
|
|
|
+ string[] strs = new string[4];
|
|
|
+ strs[0] = "openssl genrsa -out " + SubCA + ".key " + sslKey + " ";
|
|
|
+ strs[1] = "openssl req -new -" + Hash + " -nodes -key " + SubCA + ".key -out " + SubCA + ".csr -subj \"/C=TW/ST=Taipei/O=" + organizationName + "/OU=phihong_sub.IO/CN=" + commonName + "/emailAddress=phihong_sub@mail.com\" ";
|
|
|
+ //var str8 = "openssl x509 -set_serial " + sn + " -req -in " + subKeyName + ".csr -CA " + caPath + "\\" + crtName + ".crt -CAkey " + this.path + "\\" + rootCaName + ".key -CAcreateserial -out " + subKeyName + ".crt -days " + days + " -sha256 -extfile zerova_v3.cnf ";
|
|
|
+ strs[2] = "openssl x509 -set_serial " + sn + " -req -in " + SubCA + ".csr -CA " + RootCa + ".crt -CAkey " + this.path + "\\" + RootCa + ".key -CAcreateserial -out " + SubCA + ".crt -days " + Days + " -sha256 -extfile zerova_v3.cnf ";
|
|
|
+ strs[3] = CatCmd + SubCA + ".crt " + SubCA + ".key > " + SubCA + ".pem ";
|
|
|
+
|
|
|
+
|
|
|
+ for (int i = 0; i < strs.Length; i++)
|
|
|
+ {
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + strs[i],
|
|
|
+ WorkingDirectory = this.path,//"D:\\project\\vs\\ConsoleApp2",
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ string output = process.StandardOutput.ReadToEnd();
|
|
|
+ await process.WaitForExitAsync();
|
|
|
+ }
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> SignCsr(string SubCA, string RootCa, int? Days = null, string? SerialNumber = null)
|
|
|
+ {
|
|
|
+ Days ??= 3650;
|
|
|
+
|
|
|
+ if (string.IsNullOrEmpty(SerialNumber))
|
|
|
+ {
|
|
|
+ SerialNumber = await GetOpenSSLRandSn();
|
|
|
+ }
|
|
|
+ string sn = "0x" + SerialNumber;
|
|
|
+
|
|
|
+ if (await ExecShellCmd("openssl", $"x509 -set_serial {sn} -req -in {SubCA}.csr -CA {RootCa}.crt -CAkey {RootCa}.key -CAcreateserial -out {SubCA}.crt -days {Days} -sha256 -extfile zerova_v3.cnf "))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成Csr 檔案
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="Key">key 名稱</param>
|
|
|
+ /// <param name="Csr">csr 名稱</param>
|
|
|
+ /// <param name="commonName">主機名或網站地址</param>
|
|
|
+ /// <param name="organizationName">組織名稱</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> CreateCsr(
|
|
|
+ string Key,
|
|
|
+ string Csr,
|
|
|
+ string commonName,
|
|
|
+ string organizationName,
|
|
|
+ HashAlgorithm Hash = HashAlgorithm.SHA512)
|
|
|
+ {
|
|
|
+ var status = false;
|
|
|
+ var subjString = CreateSubjectString(CommonName: commonName, Organization: organizationName, Country: "TW", State: "Taipei");
|
|
|
+
|
|
|
+ if (await ExecShellCmd("openssl", $"req -new -{Hash} -nodes -key {Key}.key -out {Csr}.csr -subj \"{subjString}\" "))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+ string[] strs = new string[4];
|
|
|
+ strs[0] = "openssl req -new -SHA256 -nodes -key " + Key + ".key -out " + Csr + ".csr -subj \"/C=TW/ST=Taipei/O=" + organizationName + "/OU=phihong_sub.IO/CN=" + commonName + "/emailAddress=phihong_sub@mail.com\" ";
|
|
|
+ for (int i = 0; i < strs.Length; i++)
|
|
|
+ {
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + strs[i],
|
|
|
+ WorkingDirectory = this.path,//"D:\\project\\vs\\ConsoleApp2",
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ string output = process.StandardOutput.ReadToEnd();
|
|
|
+ await process.WaitForExitAsync();
|
|
|
+ }
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object CreateSubjectString(string CommonName = "", string Organization = "", string Country = "", string State = "")
|
|
|
+ {
|
|
|
+ ///C=TW/ST=Taipei/O={organizationName}/OU=phihong_sub.IO/CN={commonName}/emailAddress=phihong_sub@mail.com\
|
|
|
+ var toReturn = string.Empty;
|
|
|
+ if (!string.IsNullOrEmpty(Country))
|
|
|
+ {
|
|
|
+ toReturn += $"/C={Country}";
|
|
|
+ }
|
|
|
+ if (!string.IsNullOrEmpty(State))
|
|
|
+ {
|
|
|
+ toReturn += $"/ST={State}";
|
|
|
+ }
|
|
|
+ if (!string.IsNullOrEmpty(Organization))
|
|
|
+ {
|
|
|
+ toReturn += $"/O={Organization}";
|
|
|
+ }
|
|
|
+ if (!string.IsNullOrEmpty(CommonName))
|
|
|
+ {
|
|
|
+ toReturn += $"/CN={CommonName}";
|
|
|
+ }
|
|
|
+ return toReturn;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 讀取憑證資訊
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="path">檔案名稱</param>
|
|
|
+ /// <param name="fileName">檔案路徑</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string ReadCertificateHashData(string path, string fileName)//改成接收pem string 格式
|
|
|
+ {
|
|
|
+ var json = "";
|
|
|
+ var file = Path.Combine(path, fileName);
|
|
|
+ X509Certificate2 certificate = new X509Certificate2(file);
|
|
|
+
|
|
|
+
|
|
|
+ X509Extension extension = certificate.Extensions["2.5.29.35"];
|
|
|
+ var issuer_key_hash = "";
|
|
|
+ if (extension != null)
|
|
|
+ {
|
|
|
+ issuer_key_hash = extension.Format(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ string hashAlgorithm = certificate.SignatureAlgorithm.FriendlyName;
|
|
|
+
|
|
|
+
|
|
|
+ string serialNumber = certificate.SerialNumber;
|
|
|
+ byte[] issuerDER = certificate.IssuerName.RawData;
|
|
|
+ SHA1 sha1 = SHA1.Create();
|
|
|
+ byte[] hashBytes = sha1.ComputeHash(issuerDER);
|
|
|
+
|
|
|
+ var data = new
|
|
|
+ {
|
|
|
+ hashAlgorithm = hashAlgorithm,
|
|
|
+ issuerNameHash = BitConverter.ToString(hashBytes).Replace("-", ""),
|
|
|
+ issuerKeyHash = issuer_key_hash,
|
|
|
+ serialNumber = serialNumber,
|
|
|
+ thumbprint = certificate.Thumbprint
|
|
|
+ };
|
|
|
+ string thumbprint = certificate.Thumbprint;
|
|
|
+
|
|
|
+ json = JsonConvert.SerializeObject(data);
|
|
|
+ return json;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 讀取憑證資訊
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="FileName">檔案名稱</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string ReadCertificateHashData(string fileName)
|
|
|
+ {
|
|
|
+ var json = "";
|
|
|
+ var file = Path.Combine(this.path, fileName);
|
|
|
+ X509Certificate2 certificate = new X509Certificate2(file);
|
|
|
+
|
|
|
+ X509Extension extension = certificate.Extensions["2.5.29.35"];
|
|
|
+ var issuer_key_hash = "";
|
|
|
+ if (extension != null)
|
|
|
+ {
|
|
|
+ issuer_key_hash = extension.Format(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ string hashAlgorithm = certificate.SignatureAlgorithm.FriendlyName;
|
|
|
+
|
|
|
+ string serialNumber = certificate.SerialNumber;
|
|
|
+ byte[] issuerDER = certificate.IssuerName.RawData;
|
|
|
+ SHA1 sha1 = SHA1.Create();
|
|
|
+ byte[] hashBytes = sha1.ComputeHash(issuerDER);
|
|
|
+
|
|
|
+ var data = new
|
|
|
+ {
|
|
|
+ hashAlgorithm,
|
|
|
+ issuerNameHash = BitConverter.ToString(hashBytes).Replace("-", ""),
|
|
|
+ issuerKeyHash = issuer_key_hash,
|
|
|
+ serialNumber,
|
|
|
+ thumbprint = certificate.Thumbprint
|
|
|
+ };
|
|
|
+ string thumbprint = certificate.Thumbprint;
|
|
|
+
|
|
|
+ json = JsonConvert.SerializeObject(data);
|
|
|
+ return json;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// PEM 格式的憑證的內容
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="str">憑證內容</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string ReadCertificateHashDataByString(string str)
|
|
|
+ {
|
|
|
+ var json = "";
|
|
|
+ byte[] UTF8bytes = Encoding.UTF8.GetBytes(str);
|
|
|
+ X509Certificate2 certificate = new X509Certificate2(UTF8bytes);
|
|
|
+
|
|
|
+
|
|
|
+ X509Extension extension = certificate.Extensions["2.5.29.35"];
|
|
|
+ var issuer_key_hash = "";
|
|
|
+ if (extension != null)
|
|
|
+ {
|
|
|
+ issuer_key_hash = extension.Format(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ string hashAlgorithm = certificate.SignatureAlgorithm.FriendlyName;
|
|
|
+
|
|
|
+
|
|
|
+ string serialNumber = certificate.SerialNumber;
|
|
|
+ byte[] issuerDER = certificate.IssuerName.RawData;
|
|
|
+ SHA1 sha1 = SHA1.Create();
|
|
|
+ byte[] hashBytes = sha1.ComputeHash(issuerDER);
|
|
|
+
|
|
|
+ var data = new
|
|
|
+ {
|
|
|
+ hashAlgorithm = hashAlgorithm,
|
|
|
+ issuerNameHash = BitConverter.ToString(hashBytes).Replace("-", ""),
|
|
|
+ issuerKeyHash = issuer_key_hash,
|
|
|
+ serialNumber = serialNumber,
|
|
|
+ thumbprint = certificate.Thumbprint
|
|
|
+ };
|
|
|
+ string thumbprint = certificate.Thumbprint;
|
|
|
+
|
|
|
+ json = JsonConvert.SerializeObject(data);
|
|
|
+ return json;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 驗證client憑證
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="StrCA">CA憑證</param>
|
|
|
+ /// <param name="StrSub">子憑證</param>
|
|
|
+ /// <param name="Url">url localhost:3000</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> VerifyClient(string CA, string SubCA, string Url)
|
|
|
+ {
|
|
|
+ var str = "";
|
|
|
+ bool isExists = false;
|
|
|
+ if (await ExecShellCmd("openssl", $"s_client -connect {Url} -CAfile {CA} -cert {SubCA} -tls1_2 -state"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+
|
|
|
+ var str1 = "openssl s_client -connect " + Url + " -CAfile " + CA + " -cert " + SubCA + " -tls1_2 -state ";
|
|
|
+
|
|
|
+ str = await ClientCmd(str1);
|
|
|
+ string searchString = "(ok)";
|
|
|
+ string line = GetLineFromString(str, searchString);
|
|
|
+ if (line != null)
|
|
|
+ isExists = line.Contains(searchString);
|
|
|
+ return isExists;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Cmd字串指令
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="str1">字串指令</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task<string> ClientCmd(string str1)
|
|
|
+ {
|
|
|
+ var status = false;
|
|
|
+
|
|
|
+ var str = "";
|
|
|
+ string[] strs = { str1 };
|
|
|
+ for (int i = 0; i < strs.Length; i++)
|
|
|
+ {
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + strs[i],
|
|
|
+ WorkingDirectory = this.path,//"D:\\project\\vs\\ConsoleApp2",
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ //Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ var output = new List<string>();
|
|
|
+ while (process.StandardOutput.Peek() > -1)
|
|
|
+ {
|
|
|
+ output.Add(process.StandardOutput.ReadLine());
|
|
|
+ }
|
|
|
+
|
|
|
+ process.Kill();
|
|
|
+ str = string.Join("", output.ToArray());
|
|
|
+
|
|
|
+ }
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 將Root CA與Sub CA進行憑證驗證
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="Ca">CA檔案名稱</param>
|
|
|
+ /// <param name="Sub">SubCA憑證名稱</param>
|
|
|
+ /// <returns>True/Flase</returns>
|
|
|
+ public async Task<bool> VerifyCertificateByCertificate(string Sub, string Ca)
|
|
|
+ {
|
|
|
+ if (await ExecShellCmd("openssl", $"verify -CAfile {Ca} {Sub}"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var status = true;
|
|
|
+ var str = "";
|
|
|
+ var str1 = "openssl verify -CAfile " + Ca + " " + Sub;
|
|
|
+
|
|
|
+ bool isExists = false;
|
|
|
+ str = await ClientCmd(str1);
|
|
|
+ string searchString = "OK";
|
|
|
+ string line = GetLineFromString(str, searchString);
|
|
|
+ if (line != null)
|
|
|
+ isExists = line.Contains(searchString);
|
|
|
+ return isExists;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> VerifyCertificateByCertificates(string Sub, string CaPath)
|
|
|
+ {
|
|
|
+ if (await ExecShellCmd("openssl", $"verify -CApath {CaPath} {Sub}"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> CalculateHash(string CrtName,string hashName)
|
|
|
+ {
|
|
|
+ if (await ExecShellCmd("openssl", $"x509 -in {CrtName} -hash -noout -out {hashName}"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Crt轉Pem
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="CaName">檔案名稱</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> CrtToPem(string CaName)
|
|
|
+ {
|
|
|
+ if (await ExecShellCmd("openssl", $"x509 -in {CaName}.crt -out {CaName}.pem"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var status = false;
|
|
|
+ var str = "openssl x509 -in " + CaName + ".crt -out " + CaName + ".pem ";
|
|
|
+
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + str,
|
|
|
+ WorkingDirectory = this.path,
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ string output = process.StandardOutput.ReadToEnd();
|
|
|
+ await process.WaitForExitAsync();
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Pem轉Crt
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="CaName">檔案名稱</param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<bool> PemToCrt(string CaName)
|
|
|
+ {
|
|
|
+ if (await ExecShellCmd("openssl", $"x509 -outform der -in {CaName}.pem -out {CaName}.crt"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var status = false;
|
|
|
+ var str = "openssl x509 -outform der -in " + CaName + ".pem -out " + CaName + ".crt ";
|
|
|
+
|
|
|
+ var process = new Process
|
|
|
+ {
|
|
|
+ StartInfo = new ProcessStartInfo
|
|
|
+ {
|
|
|
+ FileName = ExecuteShell,
|
|
|
+ Arguments = "/C " + str,
|
|
|
+ WorkingDirectory = this.path,
|
|
|
+ RedirectStandardOutput = true,
|
|
|
+ UseShellExecute = false,
|
|
|
+ Verb = "runas"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ process.Start();
|
|
|
+ string output = process.StandardOutput.ReadToEnd();
|
|
|
+ await process.WaitForExitAsync();
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> CreateKey(string keyName,
|
|
|
+ OpensslGenrsaRsa RsaKey = OpensslGenrsaRsa.Key4096)
|
|
|
+ {
|
|
|
+ var sslKey = (int)RsaKey;
|
|
|
+ if (await ExecShellCmd("openssl", $"genrsa -out {keyName}.key {sslKey}"))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 產生資料夾
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="path"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CreateFolder(string path)
|
|
|
+ {
|
|
|
+ string subPath = path;
|
|
|
+ bool status = true;
|
|
|
+ bool exists = Directory.Exists(subPath);
|
|
|
+ status = !exists;
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(subPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 確認檔案是否存在
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="filePath"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CheckFiles(string FilePath)
|
|
|
+ {
|
|
|
+ bool status = true;
|
|
|
+ bool exists = File.Exists(FilePath);
|
|
|
+ status = exists;
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 檔案搬移
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="file"></param>
|
|
|
+ /// <param name="moveTo"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool MoveFile(string file, string moveTo)
|
|
|
+ {
|
|
|
+ bool status = false;
|
|
|
+ if (CheckFiles(file) &&
|
|
|
+ !CheckFiles(moveTo))
|
|
|
+ {
|
|
|
+ //File.Move(file, moveTo);
|
|
|
+ File.Copy(file, moveTo, true);
|
|
|
+ status = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 取得第幾行的字串
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="InputString"></param>
|
|
|
+ /// <param name="SearchString"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private static string GetLineFromString(string InputString, string SearchString)
|
|
|
+ {
|
|
|
+ using (StringReader reader = new StringReader(InputString))
|
|
|
+ {
|
|
|
+ int lineNumber = 1;
|
|
|
+ string line = "";
|
|
|
+ while ((line = reader.ReadLine()) != null)
|
|
|
+ {
|
|
|
+ if (line.Contains(SearchString))
|
|
|
+ {
|
|
|
+ return line;
|
|
|
+ }
|
|
|
+ lineNumber++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return reader.ReadLine();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|