Commit 6a9e1839 authored by justcoding121's avatar justcoding121

cleanup

parent 3e3698bc
......@@ -32,8 +32,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer = new ProxyServer();
//generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateTrustedRootCertificate(false);
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
proxyServer.ExceptionFunc = exception => Console.WriteLine(exception.Message);
proxyServer.ForwardToUpstreamGateway = true;
......
......@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.UnitTests
mgr.CertificateEngine = CertificateEngine.DefaultWindows;
mgr.CreateRootCertificate(true);
mgr.TrustRootCertificate();
mgr.TrustRootCertificate(true);
mgr.ClearIdleCertificates();
for (int i = 0; i < 5; i++)
......@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.UnitTests
}
await Task.WhenAll(tasks.ToArray());
mgr.RemoveTrustedRootCertificate();
mgr.RemoveTrustedRootCertificate(true);
mgr.StopClearIdleCertificates();
}
}
......
......@@ -17,6 +17,7 @@ using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Network.Certificate
{
......@@ -25,8 +26,6 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// </summary>
internal class BCCertificateMaker : ICertificateMaker
{
public static readonly Regex CNRemoverRegex = new Regex(@"^CN\s*=\s*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private const int certificateValidDays = 1825;
private const int certificateGraceDays = 366;
......@@ -149,7 +148,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
{
try
{
x509Certificate.FriendlyName = CNRemoverRegex.Replace(subjectName, string.Empty);
x509Certificate.FriendlyName = ProxyConstants.CNRemoverRegex.Replace(subjectName, string.Empty);
}
catch (PlatformNotSupportedException)
{
......
......@@ -9,6 +9,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Certificate;
using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Network
{
......@@ -70,14 +71,14 @@ namespace Titanium.Web.Proxy.Network
/// Note that this do not make the client trust the certificate!
/// This would import the root certificate to the certificate store of machine that runs this proxy server
/// </summary>
internal bool TrustRoot { get; set; } = false;
internal bool UserTrustRoot { get; set; } = false;
/// <summary>
/// Needs elevated permission. Works only on Windows.
/// <para>Puts the certificate to the local machine's certificate store.</para>
/// <para>Certutil.exe is a command-line program that is installed as part of Certificate Services</para>
/// </summary>
internal bool TrustRootAsAdministrator { get; set; } = false;
internal bool MachineTrustRootAsAdministrator { get; set; } = false;
/// <summary>
/// Select Certificate Engine
......@@ -247,10 +248,17 @@ namespace Titanium.Web.Proxy.Network
return fileName;
}
private bool FindRootCertificate(StoreLocation storeLocation)
/// <summary>
/// For CertificateEngine.DefaultWindows to work we need to also check in personal store
/// </summary>
/// <param name="storeLocation"></param>
/// <returns></returns>
private bool RootCertificateInstalled(StoreLocation storeLocation)
{
string value = $"{RootCertificate.Issuer}";
return FindCertificates(StoreName.Root, storeLocation, value).Count > 0;
return FindCertificates(StoreName.Root, storeLocation, value).Count > 0
&& (CertificateEngine != CertificateEngine.DefaultWindows
|| FindCertificates(StoreName.My, storeLocation, value).Count > 0);
}
private X509Certificate2Collection FindCertificates(StoreName storeName, StoreLocation storeLocation, string findValue)
......@@ -374,22 +382,32 @@ namespace Titanium.Web.Proxy.Network
if (!isRootCertificate && SaveFakeCertificates)
{
string path = GetCertificatePath();
string subjectName = BCCertificateMaker.CNRemoverRegex.Replace(certificateName, string.Empty);
string subjectName = ProxyConstants.CNRemoverRegex.Replace(certificateName, string.Empty);
subjectName = subjectName.Replace("*", "$x$");
subjectName = Path.Combine(path, subjectName + ".pfx");
var certificatePath = Path.Combine(path, subjectName + ".pfx");
if (!File.Exists(subjectName))
if (!File.Exists(certificatePath))
{
certificate = MakeCertificate(certificateName, isRootCertificate);
File.WriteAllBytes(subjectName, certificate.Export(X509ContentType.Pkcs12));
//store as cache
Task.Run(() =>
{
try
{
File.WriteAllBytes(certificatePath, certificate.Export(X509ContentType.Pkcs12));
}
catch (Exception e) { exceptionFunc(new Exception("Failed to save fake certificate.", e)); }
});
}
else
{
try
{
certificate = new X509Certificate2(subjectName, string.Empty, StorageFlag);
certificate = new X509Certificate2(certificatePath, string.Empty, StorageFlag);
}
catch /* (Exception e)*/
//if load failed create again
catch
{
certificate = MakeCertificate(certificateName, isRootCertificate);
}
......@@ -488,63 +506,7 @@ namespace Titanium.Web.Proxy.Network
}
}
/// <summary>
/// Load or Create Certificate : after "Test Is the root certificate used by this proxy is valid?"
/// <param name="trustRootCertificate">"Make current machine trust the Root Certificate used by this proxy" ==> True or False</param>
/// </summary>
public void EnsureRootCertificate(bool trustRootCertificate, bool trustRootCertificateAsAdmin)
{
this.TrustRoot = trustRootCertificate;
this.TrustRootAsAdministrator = trustRootCertificateAsAdmin;
EnsureRootCertificate();
}
/// <summary>
/// Create/load root if required and ensure that the root certificate is trusted.
/// </summary>
public void EnsureRootCertificate()
{
if (!CertValidated)
{
CreateRootCertificate();
if (TrustRoot)
{
TrustRootCertificate();
}
if (TrustRootAsAdministrator)
{
TrustRootCertificateAsAdmin();
}
}
}
public void ClearRootCertificate()
{
certificateCache.Clear();
rootCertificate = null;
}
public X509Certificate2 LoadRootCertificate()
{
string fileName = GetRootCertificatePath();
pfxFileExists = File.Exists(fileName);
if (!pfxFileExists)
{
return null;
}
try
{
return new X509Certificate2(fileName, PfxPassword, StorageFlag);
}
catch (Exception e)
{
exceptionFunc(e);
return null;
}
}
/// <summary>
/// Attempts to create a RootCertificate
......@@ -604,6 +566,30 @@ namespace Titanium.Web.Proxy.Network
return RootCertificate != null;
}
/// <summary>
/// Loads root certificate from current executing assembly location
/// </summary>
/// <returns></returns>
public X509Certificate2 LoadRootCertificate()
{
string fileName = GetRootCertificatePath();
pfxFileExists = File.Exists(fileName);
if (!pfxFileExists)
{
return null;
}
try
{
return new X509Certificate2(fileName, PfxPassword, StorageFlag);
}
catch (Exception e)
{
exceptionFunc(e);
return null;
}
}
/// <summary>
/// Manually load a Root certificate file(.pfx file)
/// </summary>
......@@ -627,26 +613,35 @@ namespace Titanium.Web.Proxy.Network
}
/// <summary>
/// Trusts the root certificate.
/// Trusts the root certificate in user store, optionally also in machine store
/// Machine trust would require elevated permissions
/// </summary>
public void TrustRootCertificate()
public void TrustRootCertificate(bool machineTrusted = false)
{
//current user
//currentUser\personal
InstallCertificate(StoreName.My, StoreLocation.CurrentUser);
if (!machineTrusted)
{
//currentUser\Root
InstallCertificate(StoreName.Root, StoreLocation.CurrentUser);
}
else
{
//current system
InstallCertificate(StoreName.My, StoreLocation.LocalMachine);
//this adds to both currentUser\Root & currentMachine\Root
InstallCertificate(StoreName.Root, StoreLocation.LocalMachine);
}
}
/// <summary>
/// Puts the certificate to the local machine's certificate store.
/// Needs elevated permission. Works only on Windows.
/// Puts the certificate to the user store, optionally also to machine store
/// Prompts with UAC if elevated permissions are required. Works only on Windows.
/// </summary>
/// <returns></returns>
public bool TrustRootCertificateAsAdmin()
public bool TrustRootCertificateAsAdmin(bool machineTrusted = false)
{
if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
{
......@@ -663,7 +658,6 @@ namespace Titanium.Web.Proxy.Network
var info = new ProcessStartInfo()
{
FileName = "certutil.exe",
Arguments = "-importPFX -p \"" + PfxPassword + "\" -f \"" + pfxFileName + "\"",
CreateNoWindow = true,
UseShellExecute = true,
Verb = "runas",
......@@ -671,6 +665,15 @@ namespace Titanium.Web.Proxy.Network
WindowStyle = ProcessWindowStyle.Hidden
};
if (!machineTrusted)
{
info.Arguments = "-f -user -p \"" + PfxPassword + "\" -importpfx root \"" + pfxFileName + "\"";
}
else
{
info.Arguments = "-importPFX -p \"" + PfxPassword + "\" -f \"" + pfxFileName + "\"";
}
try
{
var process = Process.Start(info);
......@@ -683,8 +686,9 @@ namespace Titanium.Web.Proxy.Network
File.Delete(pfxFileName);
}
catch
catch (Exception e)
{
exceptionFunc(e);
return false;
}
......@@ -692,37 +696,112 @@ namespace Titanium.Web.Proxy.Network
}
/// <summary>
/// Removes the trusted certificates.
/// Ensure certificates are setup (creates if required) & root certificate is trusted.
/// </summary>
public void EnsureRootCertificate(bool machineTrustRootCertificate = false)
{
if (!CertValidated)
{
CreateRootCertificate();
if (UserTrustRoot)
{
TrustRootCertificate(machineTrustRootCertificate);
}
if (MachineTrustRootAsAdministrator)
{
TrustRootCertificateAsAdmin();
}
}
}
/// <summary>
/// Ensure certificates are setup (creates if required) & root certificate is trusted.
/// </summary>
public void EnsureRootCertificate(bool userTrustRootCertificate, bool machineTrustRootCertificate, bool machineTrustRootCertificateAsAdmin)
{
UserTrustRoot = userTrustRootCertificate;
MachineTrustRootAsAdministrator = machineTrustRootCertificateAsAdmin;
EnsureRootCertificate(machineTrustRootCertificate);
}
/// <summary>
/// Determines whether the root certificate is trusted.
/// </summary>
public bool IsRootCertificateUserTrusted()
{
return RootCertificateInstalled(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
}
/// <summary>
/// Determines whether the root certificate is machine trusted.
/// </summary>
public bool IsRootCertificateMachineTrusted()
{
return RootCertificateInstalled(StoreLocation.LocalMachine);
}
/// <summary>
/// Removes the trusted certificates from user store, optionally also from machine store
/// To remove from machine store elevated permissions are required (will fail silently otherwise)
/// </summary>
public void RemoveTrustedRootCertificate()
public void RemoveTrustedRootCertificate(bool machineTrusted = false)
{
//current user
//currentUser\personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
if (!machineTrusted)
{
//currentUser\Root
UninstallCertificate(StoreName.Root, StoreLocation.CurrentUser, RootCertificate);
}
else
{
//current system
UninstallCertificate(StoreName.My, StoreLocation.LocalMachine, RootCertificate);
//this removes from both currentUser\Root & currentMachine\Root
//this adds to both currentUser\Root & currentMachine\Root
UninstallCertificate(StoreName.Root, StoreLocation.LocalMachine, RootCertificate);
}
}
/// <summary>
/// Removes the trusted certificates from the local machine's certificate store.
/// Needs elevated permission. Works only on Windows.
/// Removes the trusted certificates from user store, optionally also from machine store
// Prompts with UAC if elevated permissions are required. Works only on Windows.
/// </summary>
/// <returns></returns>
public bool RemoveTrustedRootCertificateAsAdmin()
public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false)
{
if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
{
return false;
}
//currentUser\Personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
var infos = new List<ProcessStartInfo>()
var infos = new List<ProcessStartInfo>();
if (!machineTrusted)
{
//currentUser\Root
infos.Add(new ProcessStartInfo()
{
FileName = "certutil.exe",
Arguments = "-delstore -user Root \"" + RootCertificateName + "\"",
CreateNoWindow = true,
UseShellExecute = true,
Verb = "runas",
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden
});
}
else
{
infos.AddRange(
new List<ProcessStartInfo>() {
//currentMachine\Personal
new ProcessStartInfo(){
FileName = "certutil.exe",
......@@ -743,7 +822,8 @@ namespace Titanium.Web.Proxy.Network
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden
}
};
});
}
var success = true;
try
......@@ -766,24 +846,18 @@ namespace Titanium.Web.Proxy.Network
}
return success;
}
/// <summary>
/// Determines whether the root certificate is trusted.
/// </summary>
public bool IsRootCertificateTrusted()
{
return FindRootCertificate(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
return true;
}
/// <summary>
/// Determines whether the root certificate is machine trusted.
/// </summary>
public bool IsRootCertificateMachineTrusted()
public void ClearRootCertificate()
{
return FindRootCertificate(StoreLocation.LocalMachine);
certificateCache.Clear();
rootCertificate = null;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
......
......@@ -245,8 +245,8 @@ namespace Titanium.Web.Proxy
}
CertificateManager = new CertificateManager(ExceptionFunc);
CertificateManager.TrustRoot = trustRootCertificate;
CertificateManager.TrustRootAsAdministrator = trustRootCertificateAsAdmin;
CertificateManager.UserTrustRoot = trustRootCertificate;
CertificateManager.MachineTrustRootAsAdministrator = trustRootCertificateAsAdmin;
if (rootCertificateName != null)
{
......
namespace Titanium.Web.Proxy.Shared
using System.Text.RegularExpressions;
namespace Titanium.Web.Proxy.Shared
{
/// <summary>
/// Literals shared by Proxy Server
......@@ -13,5 +15,7 @@
internal static readonly char[] EqualSplit = { '=' };
internal static readonly byte[] NewLine = {(byte)'\r', (byte)'\n' };
public static readonly Regex CNRemoverRegex = new Regex(@"^CN\s*=\s*", RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment