I've created a windows service which uses a HttpListener to respond to some third-party requests using .NET Framework 4.0. The listener is bound to a https prefix via the following:
listener.Prefixes.Add("https://+:" + Properties.Settings.Default.ListeningPort.ToString() + "/");
The service also self registers the https certificate in the computer store via:
X509Certificate2 certificate = new X509Certificate2(Properties.Settings.Default.HttpsCertPath, "", X509KeyStorageFlags.MachineKeySet);
X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
Further more, the service also registers the certificate - ip:port binding in Http API using the following:
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "netsh";
psi.Arguments = "http add sslcert ipport=0.0.0.0:" + Properties.Settings.Default.ListeningPort.ToString() + " certhash=" + certificate.Thumbprint + " appid=" + appId;
Process proc = Process.Start(psi);
proc.WaitForExit();
psi.Arguments = "http add sslcert ipport=[::]:" + Properties.Settings.Default.ListeningPort.ToString() + " certhash=" + certificate.Thumbprint + " appid=" + appId;
Process proc = Process.Start(psi);
proc.WaitForExit();
Everything works well, as expected... EXCEPT... (and here comes the EVIL part): After running for some time, an hour or so, listener.GetContext() no longer returns and the clients get dropped with a "connection reset" like error.
After long and painful investigations I discovered that the error was at the HTTP API level and the failure would occur during the SSL handshake, hence the listener.GetContext() not returning at all. Even more, I discovered that with every failed request, in the System log in Windows Event Log, the following errors would get logged:
Source Schannel: A fatal error occurred when attempting to access the SSL server credential private key. The error code returned from the cryptographic module is 0x8009030D. The internal error state is 10001.
and
Source HttpEvent: An error occurred while using SSL configuration for endpoint 0.0.0.0:9799. The error status code is contained within the returned data.
Further digging into the problem I noticed that once, the private key disappeared from the installed certificate. That, combined with what I read at this link, made me think different. So I gave this a try:
X509Certificate2 certificate = new X509Certificate2(Properties.Settings.Default.HttpsCertPath, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Basically, I've put in the X509KeyStorageFlags.Exportable (Remember the error you get when creating a SSL binding if you don't mark the certificate as exportable on IIS?) and X509KeyStorageFlags.PersistKeySet flags.
That seems to have done the job. The service has been running for almost two days now and still joyfully accepting incoming connections.
Hope this will spare someone from the trouble I went through.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With