c#-带有SSL证书的HttpListener挂在GetContext()上

codeday· 2019-10-30
本文来自 codeday ,作者 codeday
我创建了一个Windows服务,该服务使用HttpListener来使用.NET Framework 4.0响应某些第三方请求.侦听器通过以下方式绑定到https前缀:

listener.Prefixes.Add("https://+:" + Properties.Settings.Default.ListeningPort.ToString() + "/");

该服务还可以通过以下方式在计算机存储中自行注册https证书:

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();

此外,该服务还使用以下命令在Http API中注册证书-ip:port绑定:

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();

一切都按预期进行,除了…(这是EVIL部分):
运行一段时间(约一个小时)后,listener.GetContext()不再返回,并且客户端因“连接重置”(如错误)而掉线.

最佳答案
经过长时间艰苦的研究,我发现该错误是在HTTP API级别上,并且该失败将在SSL握手期间发生,因此listener.GetContext()根本没有返回.此外,我发现,对于每个失败的请求,Windows事件日志中的系统日志中都会记录以下错误:

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.

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.

进一步研究这个问题后,我注意到,一旦私钥从安装的证书中消失了.结合我在this link上阅读的内容,我有了不同的看法.因此,我尝试了一下:

X509Certificate2 certificate = new X509Certificate2(Properties.Settings.Default.HttpsCertPath, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

基本上,我已经输入了X509KeyStorageFlags.Exportable(如果您没有将证书标记为在IIS上可导出,还记得创建SSL绑定时遇到的错误吗)和X509KeyStorageFlags.PersistKeySet标志.
这似乎已经完成了工作.该服务已经运行了将近两天,并且仍然很高兴地接受传入的连接.

希望这可以使某人摆脱我遇到的麻烦.