SslStream.AuthenticateAsServer 异常 - 服务器模式 SSL 必须使用具有关联私钥的证书
Posted
技术标签:
【中文标题】SslStream.AuthenticateAsServer 异常 - 服务器模式 SSL 必须使用具有关联私钥的证书【英文标题】:SslStream.AuthenticateAsServer exception - The server mode SSL must use a certificate with the associated private key 【发布时间】:2013-02-03 09:28:56 【问题描述】:我正在开发一个类似于 CCProxy 的代理服务器应用程序。它适用于 HTTP 但不适用于 HTTPS。当在 SslStream 对象上调用 AuthenticateAsServer() 方法时,它会抛出异常。 我也不知道我是否提供了正确的证书,我不知道如何创建证书。我刚刚提供了我在网上下载的代码附带的证书。 代码如下:
private static void DoHttpProcessing(TcpClient client)
Stream clientStream = client.GetStream();
Stream outStream = clientStream;
SslStream sslStream = null;
StreamReader clientStreamReader = new StreamReader(clientStream);
CacheEntry cacheEntry = null;
MemoryStream cacheStream = null;
if (Server.DumpHeaders || Server.DumpPostData || Server.DumpResponseData)
Monitor.TryEnter(_outputLockObj, TimeSpan.FromMilliseconds(-1.0));
try
//read the first line HTTP command
String httpCmd = clientStreamReader.ReadLine();
if (String.IsNullOrEmpty(httpCmd))
clientStreamReader.Close();
clientStream.Close();
return;
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0];
String remoteUri = splitBuffer[1];
Version version = new Version(1, 0);
HttpWebRequest webReq;
HttpWebResponse response = null;
if (splitBuffer[0].ToUpper() == "CONNECT")
remoteUri = "https://" + splitBuffer[1];
while (!String.IsNullOrEmpty(clientStreamReader.ReadLine())) ;
StreamWriter connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine("HTTP/1.0 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: 0", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("Proxy-agent: matt-dot-net");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
sslStream = new SslStream(clientStream, false);
try
// HERE I RECEIVE EXCEPTION
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
catch (Exception ex)
Console.WriteLine(ex.Message);
sslStream.Close();
clientStreamReader.Close();
connectStreamWriter.Close();
clientStream.Close();
return;
//further code goes here...
此外,如果我使用 ssStream.AuthenticateAsClient 方法而不是 sslStream.AuthenticateAsServer,我会收到 AuthenticationException 并显示消息“对 SSPI 的调用失败,请参阅内部异常”。并且 InnerException 将消息显示为“收到的消息意外或格式错误”
当我使用 sslstream.AuthenticateAsServer() 方法时,我需要为每个新的 HTTPS 主机创建证书并使用此方法传递它。如果我提供自签名证书,则请求成功。但问题是,对于多少新的 HTTPS 请求,我将继续手动创建证书并将其分配给 AuthenticateAsServer()?
【问题讨论】:
【参考方案1】:对于服务器端证书,大多数 证书对应一个 FQDN(因此 server1.localhost.local),尽管可以有通配符证书 (*.localhost.local)。当您使用 AuthenticateAsClient 方法时,这可能是两件事之一,1)证书没有用于客户端身份验证的扩展密钥用法或 2)您没有传递正确的密码来读取证书/私钥。为了快速克服这两个障碍,我建议创建一个 OpenSSL CA,然后生成一个 CA 和服务器证书。有大量关于如何执行此操作的文档,对于以前从未创建过文档的人来说,最多需要 30 分钟......(另外我建议将证书导出到 pkcs12 扩展中,以便 CA 与服务器证书链接)。
【讨论】:
感谢 Jladd 的回答。我相信 AuthenticateAsServer 是正确的使用方法。因为我的代理应用程序充当客户端的服务器。当我使用它时,它部分工作。部分原因是,客户端浏览器发出错误的证书警告,因为它期望证书具有相同的 URL。有没有办法下载和转发来自服务器的相同证书?或者,请您演示一下解决此问题的代码吗? 您可以在浏览器中下载证书并在其中添加一个例外,说明始终接受此 URL 的此证书。但是您将无法在代码中执行此操作。现在,如果您还想要一种比这更简单的方法,您可以进入您的主机文件并在其中添加一行,该行使用指向您的代理服务 IP 的证书的 URL 和 poof,它会认为域实际上指出那里(注意:那应该只是在测试阶段。)我还查看了您的代码,您将希望摆脱 SslProtocols.Ssl2,因为 SSL V2 非常不安全且过时 在浏览器中添加异常不是正确的解决方案。因为客户端每次都会不断请求新的 URL,并且客户端不可能每次都添加异常。抱歉,jlAdd,我觉得您评论的其余部分有真正的解决方案,但我仍然无法理解该做什么作为行动。能否请您提供一些教程或将代码发送给我?感谢您的回复。以上是关于SslStream.AuthenticateAsServer 异常 - 服务器模式 SSL 必须使用具有关联私钥的证书的主要内容,如果未能解决你的问题,请参考以下文章