带有挂在 GetContext() 上的 SSL 证书的 HttpListener
HttpListener with SSL certificate hanging on GetContext()
我创建了一个 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();
此外,该服务还注册了证书 - ip:port 绑定在 Http API 中使用以下内容:
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();
一切正常,正如预期的那样......除了......(邪恶的部分来了):
在 运行 一段时间后,一个小时左右,listener.GetContext() 不再 returns 并且客户端因 "connection reset" 之类的错误而被丢弃。
经过漫长而痛苦的调查,我发现错误是在 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
标志.
这似乎已经完成了工作。该服务已经 运行 将近两天了,并且仍然很高兴地接受传入连接。
希望这能让别人免于遇到我遇到的麻烦。
我创建了一个 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();
此外,该服务还注册了证书 - ip:port 绑定在 Http API 中使用以下内容:
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();
一切正常,正如预期的那样......除了......(邪恶的部分来了): 在 运行 一段时间后,一个小时左右,listener.GetContext() 不再 returns 并且客户端因 "connection reset" 之类的错误而被丢弃。
经过漫长而痛苦的调查,我发现错误是在 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
标志.
这似乎已经完成了工作。该服务已经 运行 将近两天了,并且仍然很高兴地接受传入连接。
希望这能让别人免于遇到我遇到的麻烦。