Commit 9c30df1f authored by Honfika's avatar Honfika

Allow to query the root certificate status (IsRootCertificateTrusted and...

Allow to query the root certificate status (IsRootCertificateTrusted and IsRootCertificateMachineTrusted)
Allow to machine trust the root certificate (it will show the UAC dialog when required)
parent 2a7d7a1c
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
......@@ -30,7 +31,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// A class to manage SSL certificates used by this proxy server
/// </summary>
public class CertificateManager : IDisposable
public sealed class CertificateManager : IDisposable
{
internal CertificateEngine Engine
{
......@@ -147,7 +148,7 @@ namespace Titanium.Web.Proxy.Network
return fileName;
}
internal X509Certificate2 LoadRootCertificate()
private X509Certificate2 LoadRootCertificate()
{
var fileName = GetRootCertificatePath();
if (!File.Exists(fileName)) return null;
......@@ -218,6 +219,51 @@ 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.
/// </summary>
/// <returns></returns>
public bool TrustRootCertificateAsAdministrator()
{
if (RunTime.IsRunningOnMono())
{
return false;
}
var fileName = Path.GetTempFileName();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12));
var info = new ProcessStartInfo
{
FileName = "certutil.exe",
Arguments = "-importPFX -Enterprise -p \"\" -f \"" + fileName + "\"",
CreateNoWindow = true,
UseShellExecute = true,
Verb = "runas",
ErrorDialog = false,
};
try
{
var process = Process.Start(info);
if (process == null)
{
return false;
}
process.WaitForExit();
File.Delete(fileName);
}
catch
{
return false;
}
return true;
}
/// <summary>
/// Removes the trusted certificates.
/// </summary>
......@@ -230,13 +276,49 @@ namespace Titanium.Web.Proxy.Network
RemoveTrustedRootCertificates(StoreLocation.LocalMachine);
}
/// <summary>
/// Determines whether the root certificate is trusted.
/// </summary>
public bool IsRootCertificateTrusted()
{
return FindRootCertificate(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
}
/// <summary>
/// Determines whether the root certificate is machine trusted.
/// </summary>
public bool IsRootCertificateMachineTrusted()
{
return FindRootCertificate(StoreLocation.LocalMachine);
}
private bool FindRootCertificate(StoreLocation storeLocation)
{
string value = $"{RootCertificate.Issuer}";
return FindCertificates(StoreName.Root, storeLocation, value).Count > 0;
}
private X509Certificate2Collection FindCertificates(StoreName storeName, StoreLocation storeLocation, string findValue)
{
X509Store x509Store = new X509Store(storeName, storeLocation);
try
{
x509Store.Open(OpenFlags.OpenExistingOnly);
return x509Store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, findValue, false);
}
finally
{
x509Store.Close();
}
}
/// <summary>
/// Create an SSL certificate
/// </summary>
/// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param>
/// <returns></returns>
internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
internal X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
{
if (certificateCache.ContainsKey(certificateName))
{
......@@ -317,7 +399,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// <param name="storeLocation"></param>
/// <returns></returns>
internal void TrustRootCertificate(StoreLocation storeLocation)
private void TrustRootCertificate(StoreLocation storeLocation)
{
if (RootCertificate == null)
{
......@@ -328,7 +410,7 @@ namespace Titanium.Web.Proxy.Network
return;
}
X509Store x509RootStore = new X509Store(StoreName.Root, storeLocation);
var x509RootStore = new X509Store(StoreName.Root, storeLocation);
var x509PersonalStore = new X509Store(StoreName.My, storeLocation);
try
......@@ -357,7 +439,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// <param name="storeLocation"></param>
/// <returns></returns>
internal void RemoveTrustedRootCertificates(StoreLocation storeLocation)
private void RemoveTrustedRootCertificates(StoreLocation storeLocation)
{
if (RootCertificate == null)
{
......@@ -368,7 +450,7 @@ namespace Titanium.Web.Proxy.Network
return;
}
X509Store x509RootStore = new X509Store(StoreName.Root, storeLocation);
var x509RootStore = new X509Store(StoreName.Root, storeLocation);
var x509PersonalStore = new X509Store(StoreName.My, storeLocation);
try
......@@ -382,7 +464,7 @@ namespace Titanium.Web.Proxy.Network
catch (Exception e)
{
exceptionFunc(
new Exception("Failed to make system trust root certificate "
new Exception("Failed to remove root certificate trust "
+ $" for {storeLocation} store location. You may need admin rights.", e));
}
finally
......@@ -392,6 +474,9 @@ namespace Titanium.Web.Proxy.Network
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
}
......
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