Reputation: 15410
So the Microsoft.Web.Administration API is very easy to use to create HTTP and HTTPS bindings for sites:
using (ServerManager manager = new ServerManager())
{
Site site = manager.Sites[siteName];
site.Bindings.Clear();
site.Bindings.Add("*:80:", "http");
site.Bindings.Add("*:443:", "https");
manager.CommitChanges();
}
But the HTTPS binding is pretty meaningless without the SSL certificate. How can I go about programatically choosing a cert file and using it with the HTTPS binding, using this API?
Upvotes: 13
Views: 12978
Reputation: 2699
I feel like it's important to highlight Devator's comment in this answer. There appears to be a bug that prevents the certificate changes from taking place and I would never have solved it without seeing this comment.
If you set the binding information to itself, this causes IIS to bind the certificate. A quick example is shown below:
binding.BindingInformation = binding.BindingInformation;
Upvotes: 1
Reputation: 3768
If you landed here and are wanting to use PowerShell to accomplish this, I put a fairly complete answer here. The simplest answer, if you know the hash of the certificate that you want to use is to do this:
cd IIS:\SslBindings
get-item Cert:\LocalMachine\My\XFX2DX02779XFD1F6F4X8435A5X26ED2X8DEFX95 | New-Item 0.0.0.0!443
Upvotes: 0
Reputation: 1789
Adding to Taylor Bird's comment but using powershell:
...
Write-Verbose ("Remove old certificate [ {0} ]... " -f $SiteHttpsBinding.GetAttributeValue("certificateHash"))
$BindingMethod=$SiteHttpsBindings.Methods["RemoveSslCertificate"]
$BindingMethodInstance=$BindingMethod.CreateInstance()
$BindingMethodInstance.Execute()
Write-Verbose ("Add new certificate [ {0} ]..." -f $AfterThumbprint)
$BindingMethod=$SiteHttpsBindings.Methods["AddSslCertificate"]
$BindingMethodInstance=$BindingMethod.CreateInstance()
$BindingMethodInstance.Input.SetAttributeValue("certificateHash", $AfterThumbprint)
$BindingMethodInstance.Input.SetAttributeValue("certificateStoreName", "My")
$BindingMethodInstance.Execute()
...
The above code snippet is useful for updating certificates without needing to remove the whole binding. I've used it for adding and updating ssl bindings on local and remote machines.
Thanks Mr. Bird for supplying the WinAPI reference.
Upvotes: 0
Reputation: 65456
As Helephant's answer is the best if you need the certificate hashes (i.e. multiple IPs on a single machine with various SSL certs), you'll need to know how to get the certificates/hashes. The few lines below demonstrate how to find the information out, as the MSDN documentation is so poor for this subject.
You can't remotely update an SSL binding using ServerManager.OpenRemote() - there appears to be a bug with this. Appcmd won't help you either.
If you want to convert a byte string back into a byte array (if you know the hash), here's how.
static void Main(string[] args)
{
var store2 = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine);
Console.WriteLine("TrustedPublisher:");
PrintCerts(store2);
Console.WriteLine();
Console.WriteLine("MY:");
store2 = new X509Store(StoreName.My, StoreLocation.LocalMachine);
PrintCerts(store2);
Console.WriteLine();
Console.WriteLine("CertificateAuthority:");
store2 = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);
PrintCerts(store2);
Console.WriteLine();
}
static string PrintHash(byte[] cert)
{
StringBuilder builder = new StringBuilder();
foreach (byte b in cert)
{
builder.AppendFormat("{0:x2}", b);
}
return builder.ToString();
}
static void PrintCerts(X509Store store)
{
store.Open(OpenFlags.OpenExistingOnly);
foreach (var cert in store.Certificates)
{
Console.Write("{0} - {1}", cert.FriendlyName, PrintHash(cert.GetCertHash()));
Console.WriteLine();
}
}
Example output:
MY:
www.awesomesite.com - cc2b5fc8216a949b58aadc21089c12b2c090f6bd
Upvotes: 7
Reputation: 17028
The Bindings.Add() method has an overload for passing in the SSL certificate. If you already have a SSL certificate, you can select it from the SSL certificate store like this:
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly);
var certificate = store.Certificates.Find(X509FindType.FindByThumbprint, the thumbprint for the key", true);
var site = _mgr.Sites[name];
site.Bindings.Add("*:4043:", certificate[0].GetCertHash(), "MY");
Once you have run the code, you can check that it has worked by running this from the command line:
netsh http show sslcert
Upvotes: 7
Reputation: 13601
There is a method overload for adding Bindings that will add the certificate to HTTP.sys correctly, see: http://msdn.microsoft.com/en-us/library/bb355650(v=VS.90).aspx
Optionally you can actually set the binding settings:
binding.CertificateHash and binding.CertificateStoreName and when commiting it will register correctly with HTTP.sys: http://msdn.microsoft.com/en-us/library/microsoft.web.administration.binding_properties(v=VS.90).aspx
Upvotes: 7
Reputation: 8017
The namespace doesn't contain an API for this, so you have to use its ConfigurationMethod
to invoke an extension to the Win API that performs this function. Something like:
string certificateHash = <hash>
string certificateStore = <storename> #my, localmachine, etc
ConfigurationMethod method = binding.Methods["AddSslCertificate"];
ConfigurationMethodInstance mi = method.CreateInstance();
mi.Input.SetAttributeValue("certificateHash", certificateHash);
mi.Input.SetAttributeValue("certificateStoreName", certificateStore);
mi.Execute();
Upvotes: 2