2

I'm using Microsoft.Web.Administration (inside a Wix CustomAction) to configure Server Name Indication and bind to an existing server certificate on a IIS 8.5 site.

Turns out, setting SNI takes off the certificate binding. The following code will make things clearer:

using Microsoft.Web.Administration;

var binding = site.Bindings.FirstOrDefault(x => x.IsIPPortHostBinding && x.Host == sitename);

binding.CertificateHash = certificate.GetCertHash();
binding.CertificateStoreName = store.Name;

// this statement is causing the certificate info to get messed up.
binding["sslFlags"] = 1; // or binding.SetAttributeValue("sslFlags", 1);

Results:

With binding["sslFlags"] = 1; enter image description here

Without binding["sslFlags"] = 1; enter image description here

Is this a bug or am I missing something? How can get both SNI and Certificate binding to stick?

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
Mrchief
  • 75,126
  • 20
  • 142
  • 189

3 Answers3

2

It seems Microsoft.Web.Administration v7.0 is the culprit here. This is the official one on NuGet gallery and it seems that it is meant for IIS 7 mainly (I mean it'll work for features common in both IIS 7 & 8 but anything that 7 doesn't have will have weird results like above).

Using IIS.Microsoft.Web.Adminstration (which seems to be a community uploaded package for IIS 8.5) works. Got the hint from this answer.

Updated code:

binding.CertificateHash = certificate.GetCertHash();
binding.CertificateStoreName = store.Name;

binding.SslFlags = SslFlags.Sni;  // <<< notice it has helpful enums
Community
  • 1
  • 1
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • 1
    That stupid NuGet package is not OFFICIAL if you compare with other Microsoft official ones. The latter is neither recommend. Your application should always refer to the version installed on the machine under system32\inetsrv and never copy it locally. – Lex Li May 30 '15 at 00:04
  • NuGet packages are ***not*** stupid. They are the _way forward_. Installing humongous SDks in order to use 1 or 2 libraries is a thing of past. I don't know if you've noticed, but MS has been moving away from such approaches. Besides, in this case, I've to install IIS 8 SDK on every developer's box, every build server just to get one project compiling. Either that or I include DLLs in my SCM (ugh). Anyway, this package is just a wrapper around IIS 8 DLLs which is what MS should have done but I guess they have other priorities. If MS comes up with an official, I'd be happy to use that! – Mrchief May 30 '15 at 01:57
  • This Microsoft.Web.Administration and IIS.Microsoft.Web.Administration packages are stupid in the following aspects: 1) Microsoft owns those assemblies, not the publishers. They might violate the end user licensing agreement by publishing NuGet packages like this to include such assemblies. There are of course other NuGet packages that can violate such basic rules. 2) MWA is designed in a way to bind to OS native resources via COM, so it is OS dependent and not suitable for NuGet deployment at all. By providing this answer, you simply mislead future readers. – Lex Li May 30 '15 at 02:44
  • Mind you that this is a Wix installer. Without IIS, it wont even run. Nuget allows devs and build servers to compile and package the MSI, which just need to be DLL to be physically present. So I don't see why you're so concerned about this. – Mrchief May 30 '15 at 03:03
1

This works for me with Microsoft.Web.Administration 7.0.0.0:

public static void CreateSiteHttps(string siteName, string physicalPath)
{
    using (var serverManager = new ServerManager())
    {
        var applicationPool = serverManager.ApplicationPools.Add(siteName);
        applicationPool["startMode"] = "AlwaysRunning";

        var x509Store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        x509Store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

        var certificate = x509Store.Certificates.Find(X509FindType.FindBySubjectName, "MyCertSubjectName", false)[0];

        var hash = certificate.GetCertHash();

        var site = serverManager.Sites.Add(siteName, $"*:443:{siteName}", physicalPath, hash);
        site.ServerAutoStart = true;
        site.Bindings[0]["sslFlags"] = 1;
        site.ApplicationDefaults.ApplicationPoolName = applicationPool.Name;
        site.ApplicationDefaults.EnabledProtocols = "http,https";

        serverManager.CommitChanges();
    }
}
magnusarinell
  • 1,127
  • 14
  • 22
1

The certificate is removed when enabling SNI. You can simply get the certificate before and set it again after enabling SNI:

var cert = mySslBinding.CertificateHash;
mySslBinding.SetAttributeValue("SslFlags", Convert.ToInt32(1));
mySslBinding.CertificateHash = cert;
Florian Winter
  • 4,750
  • 1
  • 44
  • 69