Commit 6b4a035e authored by justcoding121's avatar justcoding121

#180 #199

Fix Certificate Maker for Windows to support alt names
parent 3838d9e8
...@@ -21,7 +21,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -21,7 +21,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//optionally set the Certificate Engine //optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported //Under Mono only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle; //proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
requestBodyHistory = new Dictionary<Guid, string>(); requestBodyHistory = new Dictionary<Guid, string>();
} }
......
...@@ -123,7 +123,8 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -123,7 +123,8 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="signingCertificate">The signing certificate.</param> /// <param name="signingCertificate">The signing certificate.</param>
/// <returns>X509Certificate2 instance.</returns> /// <returns>X509Certificate2 instance.</returns>
/// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception> /// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception>
private X509Certificate2 MakeCertificateInternal(bool isRoot, string fullSubject, DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate) private X509Certificate2 MakeCertificateInternal(bool isRoot, string fullSubject,
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{ {
if (isRoot != (null == signingCertificate)) if (isRoot != (null == signingCertificate))
{ {
...@@ -143,7 +144,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -143,7 +144,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param> /// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param>
/// <param name="signingCert">The signing cert.</param> /// <param name="signingCert">The signing cert.</param>
/// <returns>X509Certificate2.</returns> /// <returns>X509Certificate2.</returns>
private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot, bool switchToMtaIfNeeded, X509Certificate2 signingCert = null, CancellationToken cancellationToken = default(CancellationToken)) private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot,
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default(CancellationToken))
{ {
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
......
...@@ -8,8 +8,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -8,8 +8,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary> /// <summary>
/// Certificate Maker - uses MakeCert /// Certificate Maker - uses MakeCert
/// Calls COM objects using reflection
/// </summary> /// </summary>
public class WinCertificateMaker: ICertificateMaker public class WinCertificateMaker : ICertificateMaker
{ {
private readonly Type typeX500DN; private readonly Type typeX500DN;
...@@ -53,6 +54,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -53,6 +54,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeBasicConstraints = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionBasicConstraints"); typeBasicConstraints = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionBasicConstraints");
typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate"); typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate");
typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment"); typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment");
} }
/// <summary> /// <summary>
...@@ -62,143 +64,211 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -62,143 +64,211 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="isRoot"></param> /// <param name="isRoot"></param>
/// <param name="signingCert"></param> /// <param name="signingCert"></param>
/// <returns></returns> /// <returns></returns>
public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot,X509Certificate2 signingCert=null) public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot, X509Certificate2 signingCert = null)
{ {
return MakeCertificateInternal(sSubjectCN, isRoot, true, signingCert); return MakeCertificateInternal(sSubjectCN, isRoot, true, signingCert);
} }
private X509Certificate2 MakeCertificate(bool IsRoot, string FullSubject, int PrivateKeyLength, string HashAlg, DateTime ValidFrom, DateTime ValidTo, X509Certificate2 SigningCertificate) private X509Certificate2 MakeCertificate(bool isRoot, string subject, string fullSubject,
int privateKeyLength, string hashAlg, DateTime validFrom, DateTime validTo,
X509Certificate2 signingCertificate)
{ {
if (IsRoot != (null == SigningCertificate)) if (isRoot != (null == signingCertificate))
{ {
throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(IsRoot)); throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(isRoot));
} }
var x500DN = Activator.CreateInstance(typeX500DN);
var subject = new object[] { FullSubject, 0 }; var x500CertDN = Activator.CreateInstance(typeX500DN);
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN, subject); var typeValue = new object[] { fullSubject, 0 };
var x500DN2 = Activator.CreateInstance(typeX500DN); typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500CertDN, typeValue);
if (!IsRoot)
var x500RootCertDN = Activator.CreateInstance(typeX500DN);
if (!isRoot)
{ {
subject[0] = SigningCertificate.Subject; typeValue[0] = signingCertificate.Subject;
} }
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN2, subject);
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500RootCertDN, typeValue);
object sharedPrivateKey = null; object sharedPrivateKey = null;
if (!IsRoot)
if (!isRoot)
{ {
sharedPrivateKey = _SharedPrivateKey; sharedPrivateKey = _SharedPrivateKey;
} }
if (sharedPrivateKey == null) if (sharedPrivateKey == null)
{ {
sharedPrivateKey = Activator.CreateInstance(typeX509PrivateKey); sharedPrivateKey = Activator.CreateInstance(typeX509PrivateKey);
subject = new object[] { sProviderName }; typeValue = new object[] { sProviderName };
typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
subject[0] = 2; typeValue[0] = 2;
typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
subject = new object[] { (IsRoot ? 2 : 1) }; typeValue = new object[] { (isRoot ? 2 : 1) };
typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
if (!IsRoot)
if (!isRoot)
{ {
subject = new object[] { 176 }; typeValue = new object[] { 176 };
typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
} }
subject[0] = PrivateKeyLength;
typeX509PrivateKey.InvokeMember("Length", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); typeValue[0] = privateKeyLength;
typeX509PrivateKey.InvokeMember("Length", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null); typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null);
if (!IsRoot)
if (!isRoot)
{ {
_SharedPrivateKey = sharedPrivateKey; _SharedPrivateKey = sharedPrivateKey;
} }
} }
subject = new object[1];
var obj3 = Activator.CreateInstance(typeOID); typeValue = new object[1];
subject[0] = "1.3.6.1.5.5.7.3.1";
typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, obj3, subject); var OID = Activator.CreateInstance(typeOID);
var obj4 = Activator.CreateInstance(typeOIDS); typeValue[0] = "1.3.6.1.5.5.7.3.1";
subject[0] = obj3; typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, OID, typeValue);
typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj4, subject);
var obj5 = Activator.CreateInstance(typeEKUExt); var OIDS = Activator.CreateInstance(typeOIDS);
subject[0] = obj4; typeValue[0] = OID;
typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj5, subject); typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, OIDS, typeValue);
var obj6 = Activator.CreateInstance(typeRequestCert);
subject = new[] { 1, sharedPrivateKey, string.Empty }; var EKUExt = Activator.CreateInstance(typeEKUExt);
typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, obj6, subject); typeValue[0] = OIDS;
subject = new[] { x500DN }; typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, EKUExt, typeValue);
typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, obj6, subject);
subject[0] = x500DN; var RequestCert = Activator.CreateInstance(typeRequestCert);
typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, obj6, subject);
subject[0] = ValidFrom; typeValue = new[] { 1, sharedPrivateKey, string.Empty };
typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, obj6, subject); typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, RequestCert, typeValue);
subject[0] = ValidTo; typeValue = new[] { x500CertDN };
typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, obj6, subject); typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
var obj7 = Activator.CreateInstance(typeKUExt); typeValue[0] = x500RootCertDN;
subject[0] = 176; typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj7, subject); typeValue[0] = validFrom;
var obj8 = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, obj6, null); typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
subject = new object[1]; typeValue[0] = validTo;
if (!IsRoot) typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
var KUExt = Activator.CreateInstance(typeKUExt);
typeValue[0] = 176;
typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, KUExt, typeValue);
var certificate = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, RequestCert, null);
typeValue = new object[1];
if (!isRoot)
{ {
subject[0] = obj7; typeValue[0] = KUExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
subject[0] = obj5;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject);
if (!IsRoot) typeValue[0] = EKUExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
if (!isRoot)
{ {
var obj12 = Activator.CreateInstance(typeSignerCertificate); //add alternative names
subject = new object[] { 0, 0, 12, SigningCertificate.Thumbprint }; // https://forums.iis.net/t/1180823.aspx
typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, obj12, subject);
subject = new[] { obj12 }; var typeAltNamesCollection = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames");
typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, obj6, subject); var altNameCollection = Activator.CreateInstance(typeAltNamesCollection);
var typeExtNames = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames");
var extNames = Activator.CreateInstance(typeExtNames);
var typeCAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName");
var altDnsNames = Activator.CreateInstance(typeCAlternativeName);
typeValue = new object[] { 3, subject };
typeCAlternativeName.InvokeMember("InitializeFromString", BindingFlags.InvokeMethod, null, altDnsNames, typeValue);
typeValue = new[] { altDnsNames };
typeAltNamesCollection.InvokeMember("Add", BindingFlags.InvokeMethod, null, altNameCollection, typeValue);
typeValue = new[] { altNameCollection };
typeExtNames.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, extNames, typeValue);
typeValue[0] = extNames;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
}
if (!isRoot)
{
var SignerCertificate = Activator.CreateInstance(typeSignerCertificate);
typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint };
typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, SignerCertificate, typeValue);
typeValue = new[] { SignerCertificate };
typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
} }
else else
{ {
var obj13 = Activator.CreateInstance(typeBasicConstraints); var basicConstraints = Activator.CreateInstance(typeBasicConstraints);
subject = new object[] { "true", "0" };
typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj13, subject); typeValue = new object[] { "true", "0" };
subject = new[] { obj13 }; typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, basicConstraints, typeValue);
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); typeValue = new[] { basicConstraints };
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
var obj14 = Activator.CreateInstance(typeOID);
subject = new object[] { 1, 0, 0, HashAlg }; OID = Activator.CreateInstance(typeOID);
typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, obj14, subject);
subject = new[] { obj14 }; typeValue = new object[] { 1, 0, 0, hashAlg };
typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, obj6, subject); typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, OID, typeValue);
typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, obj6, null);
var obj15 = Activator.CreateInstance(typeX509Enrollment); typeValue = new[] { OID };
subject[0] = obj6; typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, RequestCert, typeValue);
typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, obj15, subject); typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, RequestCert, null);
if (IsRoot)
var X509Enrollment = Activator.CreateInstance(typeX509Enrollment);
typeValue[0] = RequestCert;
typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue);
if (isRoot)
{ {
subject[0] = "DO_NOT_TRUST_TitaniumProxy-CE"; typeValue[0] = fullSubject;
typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, obj15, subject); typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, X509Enrollment, typeValue);
} }
subject[0] = 0;
var obj16 = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, obj15, subject); var members = typeX509Enrollment.GetMembers();
subject = new[] { 2, obj16, 0, string.Empty };
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, obj15, subject); typeValue[0] = 0;
subject = new object[] { null, 0, 1 };
var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue);
typeValue = new[] { 2, createCertRequest, 0, string.Empty };
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue);
typeValue = new object[] { null, 0, 1 };
try try
{ {
var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, obj15, subject); var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue);
return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable); return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
} }
catch (Exception) catch (Exception)
{ {
// ignored // ignored
} }
return null; return null;
} }
private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot, bool switchToMTAIfNeeded,X509Certificate2 signingCert=null) private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot,
bool switchToMTAIfNeeded,
X509Certificate2 signingCert = null)
{ {
X509Certificate2 rCert=null; X509Certificate2 rCert = null;
if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{ {
var manualResetEvent = new ManualResetEvent(false); var manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(o => ThreadPool.QueueUserWorkItem(o =>
{ {
rCert = MakeCertificateInternal(sSubjectCN, isRoot, false,signingCert); rCert = MakeCertificateInternal(sSubjectCN, isRoot, false, signingCert);
manualResetEvent.Set(); manualResetEvent.Set();
}); });
manualResetEvent.WaitOne(); manualResetEvent.WaitOne();
...@@ -219,8 +289,8 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -219,8 +289,8 @@ namespace Titanium.Web.Proxy.Network.Certificate
var graceTime = DateTime.Now.AddDays(GraceDays); var graceTime = DateTime.Now.AddDays(GraceDays);
var now = DateTime.Now; var now = DateTime.Now;
rCert = !isRoot ? MakeCertificate(false, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), signingCert) : rCert = !isRoot ? MakeCertificate(false, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), signingCert) :
MakeCertificate(true, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), null); MakeCertificate(true, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), null);
return rCert; return rCert;
} }
} }
......
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