Dynamically adding a website with an HTTPS binding pointing to a dynamically generated self-signed certificate

2

I'm currently attempting to dynamically add a new website using the Microsoft.Web.Administration library provided by IIS7+. This is going to be a part of an installation process in which a self-signed certificate needs to be added and bound to the HTTPS binding of this website.

My research took me to this post on StackOverflow which makes use of the BouncyCastle API: Generate self signed certificate on the fly. I have tried to replicate the functionality provided by IIS administration tool for creating such a certificate by making slight alterations to the code. I have modified the signature algorithm in both methods from SHA256WithRSA to SHA1WithRSA. I am also passing the SubjectName and IssuerName as the local machine's name using Dns.GetHostEntry("127.0.0.1").HostName. I'm also setting the FriendlyName property of the X509Certificate2 object. The final modification involved passing the sl parameter of the addCertToStore method as StoreLocation.LocalMachine.

The following is a snippet of the code for dynamically creating the website and adding an HTTPS binding passing the cert.GetCertHash() data as a parameter to the Site.Bindings.Add(...) method which takes in the Binding Information, Certificate Hash and the Certificate Store Name (see MSDN documentation):

using (ServerManager iisManager = new ServerManager())
{
    Site testSite = iisManager.Sites.Add(siteName, targetDir, sitePortNumber);
    testSite.Bindings.Add("*:" + sitePortNumber + ":", certificateHash, "MY");
    iisManager.CommitChanges();
}

The issue is that when attempting to commit the changes in IIS I get the following COMException:

A specified logon session does not exist. It may already have been terminated. (Exception from HRESULT: 0x80070520)

Checking what happened in IIS it seems that the certificate is present but it is not being mapped correctly:

Server Certificates

In the image linked above, the topmost certificate is the one being added dynamically i.e. the one mentioned in my post. The last one is a sample self-signed certificate created through the IIS administration tool.

HTTPS Binding Details

The image linked above shows that the mapping between the HTTPS binding and the newly created SSL certificate failed.

Personal Certificates under Local Computer -> Personal:

This image contains a list of personal certificates which are present in certificate manager under the Local Computer section. The top one is the dynamically generated one whilst the bottom one was created using the IIS administration tool.

Certificate Details

Above are the certificate details of the self-signed certificates created using the IIS administration tool (left hand side) and the dynamically generated one (right hand side).

Some of the most notable differences between the two of them are:

  1. Missing Key Usage and Enhanced Key Usage details in the dynamically generated one.
  2. The certificate status and the icon indicating that there is something wrong with it.

So the question is what is wrong with the code involving the creation of the self-signed certificate which is causing the mapping to the new IIS website to fail?

Thanks

c#
iis-7
ssl-certificate
x509certificate
bouncycastle
asked on Stack Overflow Oct 9, 2014 by technoman • edited Jan 18, 2018 by nkr

1 Answer

4

Moved the SSL certificate from current user to local machine and it worked.

Here is my code to add the certificate. I also noticed X509KeyStorageFlags.MachineKeySet was the only flag that did not produce the error.

string certPath = "c:/test2/certName.p12";
string certPass = "TestPassword";

// Create a collection object and populate it using the PFX file
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import(certPath, certPass, X509KeyStorageFlags.MachineKeySet);

foreach (X509Certificate2 cert in collection)
{

    if(cert.Subject.Equals("CN=TestServer, O=Test"))
    {
        X509Store store1 = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
        store1.Open(OpenFlags.ReadWrite);
        store1.Add(cert);
        store1.Close();
    }


    if (cert.Subject.Equals("CN=TestClient, OU=Applications, O=Test"))
    {
        X509Store store1 = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store1.Open(OpenFlags.ReadWrite);
        store1.Add(cert);
        store1.Close();
    }
}

And here is my code to create the binding

ServerManager serverManager = new ServerManager();
var site = serverManager.Sites["Default Web Site"];
site.Bindings.Add("*:443:TestClient", certificate[0].GetCertHash(), "MY");
//  site.Bindings.Add("*:443:TestClient", "https");
serverManager.CommitChanges();
answered on Stack Overflow Jun 26, 2015 by jacobian • edited Jan 18, 2018 by nkr

User contributions licensed under CC BY-SA 3.0