Unverified Commit 625db8ed authored by honfika's avatar honfika Committed by GitHub

Merge pull request #371 from mohammadlachgar/develop

**Add password to rootCert.pfx. and more...
parents a5d81a0c e1c658b4
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
...@@ -63,13 +63,39 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -63,13 +63,39 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//proxyServer.CertificateEngine = CertificateEngine.DefaultWindows; //proxyServer.CertificateEngine = CertificateEngine.DefaultWindows;
////Set a password for the .pfx file
//proxyServer.PasswordPFX = "PfxPassword";
////Set Name(path) of the Root certificate file
//proxyServer.NamePFXfile = @"C:\NameFolder\rootCert.pfx";
////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true
//proxyServer.OverwritePFXfile = true;
////save all fake certificates in folder "crts"(will be created in proxy dll directory)
////if create new Root certificate file(.pfx) ====> delete folder "crts"
//proxyServer.SaveFakeCertificates = true;
//Trust Root Certificate
proxyServer.TrustRootCertificate = true; proxyServer.TrustRootCertificate = true;
proxyServer.CertificateManager.TrustRootCertificateAsAdministrator();
proxyServer.ForwardToUpstreamGateway = true; ////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
//proxyServer.EnsureRootCertificate(true);
//or load directly certificate(As Administrator if need this)
//and At the same time chose path and password
//if password is incorrect and (overwriteRootCert=true)(RootCertificate=null) ====> replace an existing .pfx file
//note : load now (if existed)
//proxyServer.CertificateManager.LoadRootCertificate(@"C:\NameFolder\rootCert.pfx", "PfxPassword");
//proxyServer.CertificateManager.TrustRootCertificateAsAdministrator();
//proxyServer.ForwardToUpstreamGateway = true;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{ {
ExcludedHttpsHostNameRegex = new[] { "ssllabs.com" }, //ExcludedHttpsHostNameRegex = new[] { "ssllabs.com" },
//IncludedHttpsHostNameRegex = new string[0], //IncludedHttpsHostNameRegex = new string[0],
}; };
...@@ -89,7 +115,6 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -89,7 +115,6 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); }; proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); };
proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); }; proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); };
proxyServer.Start(); proxyServer.Start();
proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp);
InitializeComponent(); InitializeComponent();
......
using System; using System;
using System.IO; using System.IO;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
{ {
try try
{ {
x509Certificate.FriendlyName = subjectName; x509Certificate.FriendlyName = System.Text.RegularExpressions.Regex.Replace(subjectName, @"^CN\s*=\s*", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
} }
catch (PlatformNotSupportedException) catch (PlatformNotSupportedException)
{ {
......
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
...@@ -69,10 +69,24 @@ namespace Titanium.Web.Proxy.Network ...@@ -69,10 +69,24 @@ namespace Titanium.Web.Proxy.Network
private string rootCertificateName; private string rootCertificateName;
private bool PFXfileExists = false;
private bool clearCertificates { get; set; } private bool clearCertificates { get; set; }
private X509Certificate2 rootCertificate; private X509Certificate2 rootCertificate;
internal bool trustRootCertificate { get; set; } = false;
internal bool overwritePFXfile { get; set; } = true;
internal string passwordpfx { get; set; } = string.Empty;
internal string namePFXfile { get; set; } = string.Empty;
internal X509KeyStorageFlags storageFlag { get; set; } = X509KeyStorageFlags.Exportable;
internal bool saveFakeCertificates { get; set; }=false;
/// <summary> /// <summary>
/// Cache dictionary /// Cache dictionary
/// </summary> /// </summary>
...@@ -86,7 +100,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -86,7 +100,7 @@ namespace Titanium.Web.Proxy.Network
set set
{ {
issuer = value; issuer = value;
ClearRootCertificate(); //ClearRootCertificate();
} }
} }
...@@ -96,7 +110,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -96,7 +110,7 @@ namespace Titanium.Web.Proxy.Network
set set
{ {
rootCertificateName = value; rootCertificateName = value;
ClearRootCertificate(); //ClearRootCertificate();
} }
} }
...@@ -115,7 +129,6 @@ namespace Titanium.Web.Proxy.Network ...@@ -115,7 +129,6 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal bool CertValidated => RootCertificate != null; internal bool CertValidated => RootCertificate != null;
internal CertificateManager(Action<Exception> exceptionFunc) internal CertificateManager(Action<Exception> exceptionFunc)
{ {
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
...@@ -124,13 +137,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -124,13 +137,13 @@ namespace Titanium.Web.Proxy.Network
certificateCache = new ConcurrentDictionary<string, CachedCertificate>(); certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
} }
private void ClearRootCertificate() public void ClearRootCertificate()
{ {
certificateCache.Clear(); certificateCache.Clear();
rootCertificate = null; rootCertificate = null;
} }
private string GetRootCertificatePath() private string GetRootCertificateDirectory()
{ {
string assemblyLocation = Assembly.GetExecutingAssembly().Location; string assemblyLocation = Assembly.GetExecutingAssembly().Location;
...@@ -143,18 +156,44 @@ namespace Titanium.Web.Proxy.Network ...@@ -143,18 +156,44 @@ namespace Titanium.Web.Proxy.Network
string path = Path.GetDirectoryName(assemblyLocation); string path = Path.GetDirectoryName(assemblyLocation);
if (null == path) if (null == path)
throw new NullReferenceException(); throw new NullReferenceException();
string fileName = Path.Combine(path, "rootCert.pfx"); return path;
}
private string GetCertPath()
{
string path = GetRootCertificateDirectory();
string certPath = Path.Combine(path, "crts");
if (!Directory.Exists(certPath)) { Directory.CreateDirectory(certPath); }
return certPath;
}
private string GetRootCertificatePath()
{
string path = GetRootCertificateDirectory();
string fileName = namePFXfile;
if ((fileName == string.Empty))
{
fileName = Path.Combine(path, "rootCert.pfx");
storageFlag = X509KeyStorageFlags.Exportable;
}
return fileName; return fileName;
} }
private X509Certificate2 LoadRootCertificate() public X509Certificate2 LoadRootCertificate()
{ {
string fileName = GetRootCertificatePath(); string fileName = GetRootCertificatePath();
if (!File.Exists(fileName)) this.PFXfileExists = File.Exists(fileName);
if (!this.PFXfileExists)
{
return null; return null;
}
try try
{ {
return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable); //return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable);
return new X509Certificate2(fileName, passwordpfx, storageFlag);
} }
catch (Exception e) catch (Exception e)
{ {
...@@ -174,13 +213,22 @@ namespace Titanium.Web.Proxy.Network ...@@ -174,13 +213,22 @@ namespace Titanium.Web.Proxy.Network
{ {
if (persistToFile && RootCertificate == null) if (persistToFile && RootCertificate == null)
{ {
RootCertificate = LoadRootCertificate(); RootCertificate = LoadRootCertificate();
} }
if (RootCertificate != null) if (RootCertificate != null)
{ {
return true; return true;
} }
else
{
if ((overwritePFXfile == false) && (PFXfileExists == true))
{
return false;
}
}
try try
{ {
...@@ -195,18 +243,42 @@ namespace Titanium.Web.Proxy.Network ...@@ -195,18 +243,42 @@ namespace Titanium.Web.Proxy.Network
{ {
try try
{ {
try {
Directory.Delete(GetCertPath(), true);
} catch { }
string fileName = GetRootCertificatePath(); string fileName = GetRootCertificatePath();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12)); File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12, passwordpfx));
} }
catch (Exception e) catch (Exception e)
{ {
exceptionFunc(e); exceptionFunc(e);
} }
} }
return RootCertificate != null; return RootCertificate != null;
} }
/// <summary>
/// Manually load a Root certificate file(.pfx file)
/// </summary>
/// <param name="namePFXfile">Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as "rootCert.pfx" (and will be saved in proxy dll directory)</param>
/// <param name="password">Set a password for the .pfx file</param>
/// <param name="overwritePFXfile">true : replace an existing .pfx file if password is incorect or if RootCertificate==null</param>
/// <param name="StorageFlag"></param>
/// <returns>
/// true if succeeded, else false
/// </returns>
public bool LoadRootCertificate(string namePFXfile, string password, bool overwritePFXfile = true, X509KeyStorageFlags StorageFlag = X509KeyStorageFlags.Exportable)
{
this.namePFXfile = namePFXfile;
this.passwordpfx = password;
this.overwritePFXfile = overwritePFXfile;
this.storageFlag = StorageFlag;
RootCertificate = LoadRootCertificate();
return (RootCertificate != null);
}
/// <summary> /// <summary>
/// Trusts the root certificate. /// Trusts the root certificate.
/// </summary> /// </summary>
...@@ -232,12 +304,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -232,12 +304,12 @@ namespace Titanium.Web.Proxy.Network
} }
string fileName = Path.GetTempFileName(); string fileName = Path.GetTempFileName();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12)); File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12, passwordpfx));
var info = new ProcessStartInfo var info = new ProcessStartInfo
{ {
FileName = "certutil.exe", FileName = "certutil.exe",
Arguments = "-importPFX -p \"\" -f \"" + fileName + "\"", Arguments = "-importPFX -p \""+ passwordpfx + "\" -f \"" + fileName + "\"",
CreateNoWindow = true, CreateNoWindow = true,
UseShellExecute = true, UseShellExecute = true,
Verb = "runas", Verb = "runas",
...@@ -352,6 +424,15 @@ namespace Titanium.Web.Proxy.Network ...@@ -352,6 +424,15 @@ namespace Titanium.Web.Proxy.Network
} }
} }
private X509Certificate2 makeCertificate(string certificateName, bool isRootCertificate)
{
if (!isRootCertificate && RootCertificate == null)
{
CreateTrustedRootCertificate();
}
return certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
}
/// <summary> /// <summary>
/// Create an SSL certificate /// Create an SSL certificate
/// </summary> /// </summary>
...@@ -374,12 +455,31 @@ namespace Titanium.Web.Proxy.Network ...@@ -374,12 +455,31 @@ namespace Titanium.Web.Proxy.Network
{ {
try try
{ {
if (!isRootCertificate && RootCertificate == null) if ((isRootCertificate == false) && (saveFakeCertificates == true)) {
string path = GetCertPath();
string subjectName = System.Text.RegularExpressions.Regex.Replace(certificateName, @"^CN\s*=\s*", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
subjectName = subjectName.Replace("*", "$x$");
subjectName= Path.Combine(path, subjectName+ ".pfx");
if (!File.Exists(subjectName))
{ {
CreateTrustedRootCertificate(); certificate = this.makeCertificate(certificateName, isRootCertificate);
File.WriteAllBytes(subjectName, certificate.Export(X509ContentType.Pkcs12));
}
else
{
try
{
certificate = new X509Certificate2(subjectName, string.Empty, storageFlag);
}
catch/* (Exception e)*/
{
certificate = this.makeCertificate(certificateName, isRootCertificate);
}
}
}
else {
certificate = this.makeCertificate(certificateName, isRootCertificate);
} }
certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
} }
catch (Exception e) catch (Exception e)
{ {
......
using StreamExtended.Network; using StreamExtended.Network;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
...@@ -40,17 +40,30 @@ namespace Titanium.Web.Proxy ...@@ -40,17 +40,30 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Backing field for corresponding public property /// Backing field for corresponding public property
/// </summary> /// </summary>
private bool trustRootCertificate; private int clientConnectionCount;
/// <summary> /// <summary>
/// Backing field for corresponding public property /// Backing field for corresponding public property
/// </summary> /// </summary>
private int clientConnectionCount; private int serverConnectionCount;
/// <summary> /// <summary>
/// Backing field for corresponding public property /// Backing field for corresponding public property
/// </summary> /// </summary>
private int serverConnectionCount; private bool trustRootCertificate = false;
private bool overwritePFXfile = true;
/// <summary>
/// Password for export and load rootCert.pfx
/// </summary>
private string passwordPFX = string.Empty;
private string namePFXfile = string.Empty;
private X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable;
private bool saveFakeCertificates = false;
/// <summary> /// <summary>
/// A object that creates tcp connection to server /// A object that creates tcp connection to server
...@@ -122,11 +135,74 @@ namespace Titanium.Web.Proxy ...@@ -122,11 +135,74 @@ namespace Titanium.Web.Proxy
set set
{ {
trustRootCertificate = value; trustRootCertificate = value;
if (value) CertificateManager.trustRootCertificate = trustRootCertificate;
}
}
/// <summary>
/// Save all fake certificates in folder "crts"(will be created in proxy dll directory)
/// <para>for can load the certificate and not make new certificate every time </para>
/// </summary>
public bool SaveFakeCertificates
{ {
EnsureRootCertificate(); get => saveFakeCertificates;
set
{
saveFakeCertificates = value;
CertificateManager.saveFakeCertificates = saveFakeCertificates;
} }
} }
/// <summary>
/// Overwrite Root certificate file
/// <para>true : replace an existing .pfx file if password is incorect or if RootCertificate = null</para>
/// </summary>
public bool OverwritePFXfile
{
get => overwritePFXfile;
set
{
overwritePFXfile = value;
CertificateManager.overwritePFXfile = this.overwritePFXfile;
}
}
/// <summary>
/// Password of the Root certificate file
/// <para>Set a password for the .pfx file</para>
/// </summary>
public string PasswordPFX
{
get => passwordPFX;
set
{
passwordPFX = value;
CertificateManager.passwordpfx = this.passwordPFX;
}
}
/// <summary>
/// Name(path) of the Root certificate file
/// <para>Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as "rootCert.pfx" (and will be saved in proxy dll directory)</para>
/// </summary>
public string NamePFXfile
{
get => namePFXfile;
set
{
namePFXfile = value;
CertificateManager.namePFXfile = this.namePFXfile;
}
}
public X509KeyStorageFlags StorageFlag
{
get => storageFlag;
set
{
storageFlag = value;
CertificateManager.storageFlag = this.storageFlag;
}
} }
/// <summary> /// <summary>
...@@ -373,7 +449,6 @@ namespace Titanium.Web.Proxy ...@@ -373,7 +449,6 @@ namespace Titanium.Web.Proxy
SetAsSystemProxy(endPoint, ProxyProtocolType.Http); SetAsSystemProxy(endPoint, ProxyProtocolType.Http);
} }
/// <summary> /// <summary>
/// Set the given explicit end point as the default proxy server for current machine /// Set the given explicit end point as the default proxy server for current machine
/// </summary> /// </summary>
...@@ -406,7 +481,6 @@ namespace Titanium.Web.Proxy ...@@ -406,7 +481,6 @@ namespace Titanium.Web.Proxy
{ {
throw new Exception("Endpoint do not support Https connections"); throw new Exception("Endpoint do not support Https connections");
} }
EnsureRootCertificate(); EnsureRootCertificate();
//If certificate was trusted by the machine //If certificate was trusted by the machine
...@@ -520,6 +594,11 @@ namespace Titanium.Web.Proxy ...@@ -520,6 +594,11 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is already running."); throw new Exception("Proxy is already running.");
} }
if (ProxyEndPoints.OfType<ExplicitProxyEndPoint>().Any(x => x.GenericCertificate == null))
{
EnsureRootCertificate();
}
//clear any system proxy settings which is pointing to our own endpoint (causing a cycle) //clear any system proxy settings which is pointing to our own endpoint (causing a cycle)
//due to non gracious proxy shutdown before or something else //due to non gracious proxy shutdown before or something else
if (systemProxySettingsManager != null && RunTime.IsWindows) if (systemProxySettingsManager != null && RunTime.IsWindows)
...@@ -571,7 +650,6 @@ namespace Titanium.Web.Proxy ...@@ -571,7 +650,6 @@ namespace Titanium.Web.Proxy
} }
} }
/// <summary> /// <summary>
/// Stop this proxy server /// Stop this proxy server
/// </summary> /// </summary>
...@@ -692,7 +770,17 @@ namespace Titanium.Web.Proxy ...@@ -692,7 +770,17 @@ namespace Titanium.Web.Proxy
return Task.FromResult(proxy); return Task.FromResult(proxy);
} }
private void EnsureRootCertificate() /// <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)
{
this.TrustRootCertificate = TrustRootCertificate;
EnsureRootCertificate();
}
public void EnsureRootCertificate()
{ {
if (!CertificateManager.CertValidated) if (!CertificateManager.CertValidated)
{ {
......
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