Commit cf082423 authored by mohammadlachgar's avatar mohammadlachgar

**Add password to rootCert.pfx. and more...

**Save all fake certificates in folder "crts"(will be save in proxy dll directory)
 for can load the certificate and not make new certificate every time .
**Manually load a RootCertificate
parent a5d81a0c
......@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private int lastSessionNumber;
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public SessionListItem SelectedSession
{
......@@ -63,8 +63,24 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
proxyServer = new ProxyServer();
//proxyServer.CertificateEngine = CertificateEngine.DefaultWindows;
proxyServer.TrustRootCertificate = true;
proxyServer.CertificateManager.TrustRootCertificateAsAdministrator();
//add password to rootCert.pfx
//proxyServer.Password_rootCert = "MyPassword";
//save all fake certificates in folder "crts"(will be save in proxy dll directory)
//proxyServer.SaveFakeCertificates = true;
//proxyServer.TrustRootCertificate = true;
//or if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
proxyServer.EnsureRootCertificate(true);
//proxyServer.CertificateManager.TrustRootCertificateAsAdministrator();
proxyServer.ForwardToUpstreamGateway = true;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
......
using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Org.BouncyCastle.Asn1;
......@@ -68,7 +70,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
string issuerName, DateTime validFrom,
DateTime validTo, int keyStrength = 2048,
string signatureAlgorithm = "SHA256WithRSA",
AsymmetricKeyParameter issuerPrivateKey = null)
AsymmetricKeyParameter issuerPrivateKey = null, X509Certificate2 cloneCertificate = null)
{
// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
......@@ -98,13 +100,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}
// Subject Public Key
var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Set certificate intended purposes to only Server Authentication
......@@ -134,7 +137,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
rsa.Exponent2, rsa.Coefficient);
#if NET45
// Set private key onto certificate instance
// Set private key onto certificate instance X509Certificate2
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
#else
......@@ -146,7 +149,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
{
try
{
x509Certificate.FriendlyName = subjectName;
x509Certificate.FriendlyName = System.Text.RegularExpressions.Regex.Replace(subjectName.ToLower(), @"^" + "CN".ToLower() + @"\s*=\s*", "");
}
catch (PlatformNotSupportedException)
{
......@@ -172,7 +175,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
}
}
/// <summary>
/// Makes the certificate internal.
/// </summary>
......@@ -199,11 +202,17 @@ namespace Titanium.Web.Proxy.Network.Certificate
}
else
{
var kp = DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey);
return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo, issuerPrivateKey: kp.Private);
}
}
/// <summary>
/// Makes the certificate internal.
/// </summary>
......
......@@ -28,6 +28,9 @@ namespace Titanium.Web.Proxy.Network
BouncyCastle = 1
}
/// <summary>
/// A class to manage SSL certificates used by this proxy server
/// </summary>
......@@ -57,6 +60,30 @@ namespace Titanium.Web.Proxy.Network
}
}
private bool trustRootCertificate;
public bool TrustrootCertificate
{
get => trustRootCertificate;
set
{
trustRootCertificate = value;
}
}
private bool saveCertificate;
public bool SaveCertificate
{
get => saveCertificate;
set
{
saveCertificate = value;
}
}
private const string defaultRootCertificateIssuer = "Titanium";
private const string defaultRootRootCertificateName = "Titanium Root Certificate Authority";
......@@ -73,6 +100,8 @@ namespace Titanium.Web.Proxy.Network
private X509Certificate2 rootCertificate;
public bool only_load_rootCert { get; set; }
/// <summary>
/// Cache dictionary
/// </summary>
......@@ -80,13 +109,14 @@ namespace Titanium.Web.Proxy.Network
private readonly Action<Exception> exceptionFunc;
internal string Issuer
{
get => issuer ?? defaultRootCertificateIssuer;
set
{
issuer = value;
ClearRootCertificate();
//ClearRootCertificate();
}
}
......@@ -96,7 +126,7 @@ namespace Titanium.Web.Proxy.Network
set
{
rootCertificateName = value;
ClearRootCertificate();
//ClearRootCertificate();
}
}
......@@ -110,6 +140,18 @@ namespace Titanium.Web.Proxy.Network
}
}
private string password_rootCert = string.Empty;
public string Password_rootCert
{
get => password_rootCert;
set
{
password_rootCert = value;
}
}
/// <summary>
/// Is the root certificate used by this proxy is valid?
/// </summary>
......@@ -124,13 +166,14 @@ namespace Titanium.Web.Proxy.Network
certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
}
private void ClearRootCertificate()
public void ClearRootCertificate()
{
certificateCache.Clear();
rootCertificate = null;
}
private string GetRootCertificatePath()
private string GetRootCertificateDirectory()
{
string assemblyLocation = Assembly.GetExecutingAssembly().Location;
......@@ -143,18 +186,43 @@ namespace Titanium.Web.Proxy.Network
string path = Path.GetDirectoryName(assemblyLocation);
if (null == path)
throw new NullReferenceException();
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 = Path.Combine(path, "rootCert.pfx");
return fileName;
}
private X509Certificate2 LoadRootCertificate()
public X509Certificate2 LoadRootCertificate()
{
string fileName = GetRootCertificatePath();
string fileName = filename_loadx;
if (/*(fileName.Trim().Length<=0)||*/ (fileName == string.Empty))
{
fileName = GetRootCertificatePath();
passwordx = password_rootCert; /*string.Empty;*/
StorageFlag = X509KeyStorageFlags.Exportable;
}
if (!File.Exists(fileName))
return null;
try
{
return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable);
//return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable);
return new X509Certificate2(fileName, passwordx, StorageFlag);
}
catch (Exception e)
{
......@@ -163,6 +231,12 @@ namespace Titanium.Web.Proxy.Network
}
}
/// <summary>
/// Attempts to create a RootCertificate
/// </summary>
......@@ -174,17 +248,30 @@ namespace Titanium.Web.Proxy.Network
{
if (persistToFile && RootCertificate == null)
{
RootCertificate = LoadRootCertificate();
}
if (RootCertificate != null)
{
return true;
}
else
{
if (only_load_rootCert == true)
{
return false;
}
}
try
{
RootCertificate = CreateCertificate(RootCertificateName, true);
}
catch (Exception e)
{
......@@ -195,8 +282,16 @@ namespace Titanium.Web.Proxy.Network
{
try
{
try
{
Directory.Delete(GetCertPath(), true);
}
catch { }
string fileName = GetRootCertificatePath();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12));
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12, password_rootCert));
}
catch (Exception e)
{
......@@ -204,9 +299,54 @@ namespace Titanium.Web.Proxy.Network
}
}
return RootCertificate != null;
}
/// <summary>
/// Attempts to Manually load a RootCertificate
/// set password and path_fileCertificate
/// </summary>
/// <returns>
/// true if succeeded, else false
/// </returns>
public void SetInfo_LoadRootCertificate(string fileName, string passwordx, X509KeyStorageFlags StorageFlag = X509KeyStorageFlags.Exportable)
{
filename_loadx = fileName;
this.passwordx = passwordx;
this.StorageFlag = StorageFlag;
only_load_rootCert = true;
}
/// <summary>
/// Attempts to Manually load a RootCertificate
/// </summary>
/// <returns>
/// true if succeeded, else false
/// </returns>
public bool LoadRootCertificate(string fileName, string passwordx, X509KeyStorageFlags StorageFlag = X509KeyStorageFlags.Exportable)
{
filename_loadx = fileName;
this.passwordx = passwordx;
this.StorageFlag = StorageFlag;
only_load_rootCert = true;
RootCertificate = LoadRootCertificate();
return (RootCertificate != null);
}
private string passwordx = string.Empty;
private string filename_loadx = "";
X509KeyStorageFlags StorageFlag = X509KeyStorageFlags.Exportable;
/// <summary>
/// Trusts the root certificate.
/// </summary>
......@@ -219,6 +359,9 @@ namespace Titanium.Web.Proxy.Network
TrustRootCertificate(StoreLocation.LocalMachine);
}
/// <summary>
/// Puts the certificate to the local machine's certificate store.
/// Needs elevated permission. Works only on Windows.
......@@ -232,12 +375,12 @@ namespace Titanium.Web.Proxy.Network
}
string fileName = Path.GetTempFileName();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12));
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12, password_rootCert));
var info = new ProcessStartInfo
{
FileName = "certutil.exe",
Arguments = "-importPFX -p \"\" -f \"" + fileName + "\"",
Arguments = "-importPFX -p \"" + password_rootCert + "\" -f \"" + fileName + "\"",
CreateNoWindow = true,
UseShellExecute = true,
Verb = "runas",
......@@ -352,6 +495,17 @@ namespace Titanium.Web.Proxy.Network
}
}
private X509Certificate2 makeCertificate(string certificateName, bool isRootCertificate)
{
if (!isRootCertificate && RootCertificate == null)
{
CreateTrustedRootCertificate();
}
return certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
}
/// <summary>
/// Create an SSL certificate
/// </summary>
......@@ -374,12 +528,44 @@ namespace Titanium.Web.Proxy.Network
{
try
{
if (!isRootCertificate && RootCertificate == null)
//if (!isRootCertificate && RootCertificate == null)
// {
// CreateTrustedRootCertificate();
// }
if ((isRootCertificate == false) && (saveCertificate == true))
{
string path = GetCertPath();
string subjectName = System.Text.RegularExpressions.Regex.Replace(certificateName.ToLower(), @"^" + "CN".ToLower() + @"\s*=\s*", "");
subjectName = subjectName.Replace("*", "$x$");
subjectName = Path.Combine(path, subjectName + ".pfx");
if (!File.Exists(subjectName))
{
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
{
CreateTrustedRootCertificate();
certificate = this.makeCertificate(certificateName, isRootCertificate);
}
certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
}
catch (Exception e)
{
......@@ -402,7 +588,7 @@ namespace Titanium.Web.Proxy.Network
return cached.Certificate;
}
}
}
}
return certificate;
}
......@@ -475,6 +661,7 @@ namespace Titanium.Web.Proxy.Network
}
}
/// <summary>
/// Remove the Root Certificate trust
/// </summary>
......@@ -488,6 +675,7 @@ namespace Titanium.Web.Proxy.Network
new Exception("Could not set root certificate"
+ " as system proxy since it is null or empty."));
return;
}
......
......@@ -42,6 +42,16 @@ namespace Titanium.Web.Proxy
/// </summary>
private bool trustRootCertificate;
private bool saveCertificate = false;
/// <summary>
/// Password for export and load rootCert.pfx
/// </summary>
private string password_rootCert = string.Empty;
/// <summary>
/// Backing field for corresponding public property
/// </summary>
......@@ -122,13 +132,46 @@ namespace Titanium.Web.Proxy
set
{
trustRootCertificate = value;
if (value)
{
EnsureRootCertificate();
}
CertificateManager.TrustrootCertificate = trustRootCertificate;
//if (value)
//{
////convert to public function
///now, "Manually" call this function===> EnsureRootCertificate();
//
//}
}
}
/// <summary>
/// Save all fake certificates in folder "crts"(will be save in proxy dll directory)
/// for can load the certificate and not make new certificate every time
/// </summary>
public bool SaveFakeCertificates
{
get => saveCertificate;
set
{
saveCertificate = value;
CertificateManager.SaveCertificate = saveCertificate;
}
}
/// <summary>
/// add password to rootCert.pfx
/// </summary>
public string Password_rootCert
{
get => this.password_rootCert;
set
{
this.password_rootCert = value;
CertificateManager.Password_rootCert = this.password_rootCert;
}
}
/// <summary>
/// Select Certificate Engine
/// Optionally set to BouncyCastle
......@@ -331,6 +374,7 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint"></param>
public void AddEndPoint(ProxyEndPoint endPoint)
{
if (ProxyEndPoints.Any(x => x.IpAddress.Equals(endPoint.IpAddress) && endPoint.Port != 0 && x.Port == endPoint.Port))
{
throw new Exception("Cannot add another endpoint to same port & ip address");
......@@ -406,7 +450,6 @@ namespace Titanium.Web.Proxy
{
throw new Exception("Endpoint do not support Https connections");
}
EnsureRootCertificate();
//If certificate was trusted by the machine
......@@ -520,6 +563,18 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is already running.");
}
try
{
if (ProxyEndPoints.Any(x => (x as ExplicitProxyEndPoint).GenericCertificate == null))
{
EnsureRootCertificate();
}
}
catch
{
}
//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
if (systemProxySettingsManager != null && RunTime.IsWindows)
......@@ -692,10 +747,21 @@ namespace Titanium.Web.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)
{
CertificateManager.CreateTrustedRootCertificate();
if (TrustRootCertificate)
......@@ -705,6 +771,8 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// When a connection is received from client act
/// </summary>
......
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