diff --git a/Titanium.Web.Proxy/Network/CertificateManager.cs b/Titanium.Web.Proxy/Network/CertificateManager.cs
index 828e4f8fa..ddc9cd2ed 100644
--- a/Titanium.Web.Proxy/Network/CertificateManager.cs
+++ b/Titanium.Web.Proxy/Network/CertificateManager.cs
@@ -1,6 +1,7 @@
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 @@ public enum CertificateEngine
///
/// A class to manage SSL certificates used by this proxy server
///
- public class CertificateManager : IDisposable
+ public sealed class CertificateManager : IDisposable
{
internal CertificateEngine Engine
{
@@ -147,7 +148,7 @@ private string GetRootCertificatePath()
return fileName;
}
- internal X509Certificate2 LoadRootCertificate()
+ private X509Certificate2 LoadRootCertificate()
{
var fileName = GetRootCertificatePath();
if (!File.Exists(fileName)) return null;
@@ -218,6 +219,51 @@ public void TrustRootCertificate()
TrustRootCertificate(StoreLocation.LocalMachine);
}
+ ///
+ /// Puts the certificate to the local machine's certificate store.
+ /// Needs elevated permission. Works only on Windows.
+ ///
+ ///
+ 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 -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;
+ }
+
///
/// Removes the trusted certificates.
///
@@ -230,13 +276,49 @@ public void RemoveTrustedRootCertificates()
RemoveTrustedRootCertificates(StoreLocation.LocalMachine);
}
+ ///
+ /// Determines whether the root certificate is trusted.
+ ///
+ public bool IsRootCertificateTrusted()
+ {
+ return FindRootCertificate(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
+ }
+
+ ///
+ /// Determines whether the root certificate is machine trusted.
+ ///
+ 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();
+ }
+ }
+
///
/// Create an SSL certificate
///
///
///
///
- internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
+ internal X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
{
if (certificateCache.ContainsKey(certificateName))
{
@@ -317,7 +399,7 @@ internal async void ClearIdleCertificates(int certificateCacheTimeOutMinutes)
///
///
///
- internal void TrustRootCertificate(StoreLocation storeLocation)
+ private void TrustRootCertificate(StoreLocation storeLocation)
{
if (RootCertificate == null)
{
@@ -328,7 +410,7 @@ internal void TrustRootCertificate(StoreLocation storeLocation)
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 @@ internal void TrustRootCertificate(StoreLocation storeLocation)
///
///
///
- internal void RemoveTrustedRootCertificates(StoreLocation storeLocation)
+ private void RemoveTrustedRootCertificates(StoreLocation storeLocation)
{
if (RootCertificate == null)
{
@@ -368,7 +450,7 @@ internal void RemoveTrustedRootCertificates(StoreLocation storeLocation)
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 @@ internal void RemoveTrustedRootCertificates(StoreLocation storeLocation)
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 @@ internal void RemoveTrustedRootCertificates(StoreLocation storeLocation)
}
}
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
public void Dispose()
{
}