关于身份验证:如何将SSL添加到使用httplistener的.net应用程序-它不会在IIS上运行

关于身份验证:如何将SSL添加到使用httplistener的.net应用程序-它不会在IIS上运行

How do I add SSL to a .net application that uses httplistener - it will *not* be running on IIS

最新编辑以粗体显示
我正在使用.net HttpListener类,但不会在IIS上运行此应用程序,也不使用ASP.net。该网站描述了使用asp.net实际实现SSL的代码,并且描述了如何设置证书(尽管我不确定它是否仅适用于IIS)。

类文档描述了各种身份验证类型(基本身份验证,摘要身份验证,Windows身份验证等)---它们都不涉及SSL。它确实说如果使用HTTPS,则需要设置服务器证书。这将是单行属性设置,而HttpListener会找出其余的属性吗?

简而言之,我需要知道如何设置证书以及如何修改代码以实现SSL。

虽然在尝试访问HTTPS时没有发生,但我确实在系统事件日志中注意到一个错误-源是" Schannel",消息的内容是:

A fatal error occurred when attempting
to access the SSL server credential
private key. The error code returned
from the cryptographic module is
0x80090016.

编辑:
到目前为止已采取的步骤

  • 在C#中创建了可用于HTTP连接的有效HTTPListener(例如" http:// localhost:8089 / foldername /"
  • 使用makecert.exe创建了一个证书
  • 使用certmgr.exe添加了受信任的证书
  • 使用Httpcfg.exe侦听测试端口上的SSL连接(例如8090)
  • 通过listener.Prefixes.Add(https:// localhost:8090 / foldername /");将端口8080添加到HTTPListener。
  • 测试了HTTP客户端连接,例如(http:// localhost:8089 / foldername /")在浏览器中并收到正确的返回
  • 测试了HTTPS客户端连接,例如(http:// localhost:8090 / foldername /")在浏览器中并收到"数据传输中断"(在Firefox中)
  • 在Visual Studio中进行调试表明,HTTPS连接启动时,接收到请求的侦听器回调不会被击中-我看不到可以设置断点以捕获其他任何内容的地方。
  • netstat显示HTTPS和HTTP的侦听端口均打开。尝试连接后,HTTPS端口确实转到TIME_WAIT。
  • Fiddler和HTTPAnalyzer不会捕获任何流量,我想它在此过程中的作用还远远不足以显示在那些HTTP分析工具中

问题

  • 可能是什么问题?
  • 我是否缺少一段.Net代码(这意味着我必须在C#中做更多的工作,而不仅仅是在侦听器中添加指向HTTPS的前缀,这就是我所做的)
  • 在某处错过了配置步骤吗?
  • 我还可以做些什么来分析问题?
  • 系统事件日志中的错误消息是问题的征兆吗?如果是这样,如何解决?

我有一个类似的问题,看来证书本身可能有问题。

这是对我有用的路径:

1
makecert.exe -r -a sha1 -n CN=localhost -sky exchange -pe -b 01/01/2000 -e 01/01/2050 -ss my -sr localmachine

然后查找证书指纹,将其复制到剪贴板并删除空格。在下一个命令中,这将是-h之后的参数:

1
HttpCfg.exe set ssl -i 0.0.0.0:801 -h 35c65fd4853f49552471d2226e03dd10b7a11755

然后在https:// localhost:801 /上运行服务主机,即可正常运行。

我无法进行的工作是让https在自行生成的证书上运行。这是我运行生成的代码(为清楚起见,删除了错误处理):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
LPCTSTR pszX500 = subject;
DWORD cbEncoded = 0;
CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL);
pbEncoded = (BYTE *)malloc(cbEncoded);
CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL);

// Prepare certificate Subject for self-signed certificate
CERT_NAME_BLOB SubjectIssuerBlob;
memset(&SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
SubjectIssuerBlob.cbData = cbEncoded;
SubjectIssuerBlob.pbData = pbEncoded;

// Prepare key provider structure for self-signed certificate
CRYPT_KEY_PROV_INFO KeyProvInfo;
memset(&KeyProvInfo, 0, sizeof(KeyProvInfo));
KeyProvInfo.pwszContainerName = _T("my-container");
KeyProvInfo.pwszProvName = NULL;
KeyProvInfo.dwProvType = PROV_RSA_FULL;
KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
KeyProvInfo.cProvParam = 0;
KeyProvInfo.rgProvParam = NULL;
KeyProvInfo.dwKeySpec = AT_SIGNATURE;

// Prepare algorithm structure for self-signed certificate
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
memset(&SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

// Prepare Expiration date for self-signed certificate
SYSTEMTIME EndTime;
GetSystemTime(&EndTime);
EndTime.wYear += 5;

// Create self-signed certificate
pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob, 0, &KeyProvInfo, &SignatureAlgorithm, 0, &EndTime, 0);
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0);

证书显示正常,并且具有有效的私钥,但是https会超时,就像从未注册指纹一样。如果有人知道为什么-请评论

EDIT1:经过一番摸索,我发现CertCreateSelfSignCertificate的初始化会生成正确的证书:

1
2
3
4
5
6
7
8
9
CRYPT_KEY_PROV_INFO KeyProvInfo;
memset(&KeyProvInfo, 0, sizeof(KeyProvInfo));
KeyProvInfo.pwszContainerName = _T("my-container");
KeyProvInfo.pwszProvName = _T("Microsoft RSA SChannel Cryptographic Provider");
KeyProvInfo.dwProvType = PROV_RSA_SCHANNEL;
KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
KeyProvInfo.cProvParam = 0;
KeyProvInfo.rgProvParam = NULL;
KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;

您只需要将证书绑定到ip:port,然后使用https://前缀打开您的侦听器。 0.0.0.0适用于所有ip。 appid是任何随机的GUID,而certhash是证书的哈希(有时称为thumprint)。

使用管理员特权使用cmd.exe运行以下命令。

1
netsh http add sslcert ipport=0.0.0.0:1234 certhash=613bb67c4acaab06def391680505bae2ced4053b  appid={86476d42-f4f3-48f5-9367-ff60f2ed2cdc}

如果您想创建一个自签名证书来对此进行测试,

  • 打开IIS
  • 点击您的计算机名称
  • 单击服务器证书图标
  • 单击生成自签名证书
  • 双击并转到详细信息
  • 您将在此处看到指纹,只需删除空格即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("https://+:1234/");
    listener.Start();
    Console.WriteLine("Listening...");
    HttpListenerContext context = listener.GetContext();

    using (Stream stream = context.Response.OutputStream)
    using (StreamWriter writer = new StreamWriter(stream))
        writer.Write("hello, https world");

    Console.ReadLine();
  • 运行该程序后,我只是导航至https://localhost:1234以查看打印的文本。由于证书CN与URL不匹配,并且不在受信任的证书存储中,因此您将收到证书警告。文本是加密的,但是您可以使用Wire Shark之??类的工具进行验证。

    如果您想更多地控制创建自签名x509证书,则openssl是一个很棒的工具,并且有一个用于Windows的端口。与makecert工具相比,我获得了更多的成功。

    同样重要的是,如果要通过带有ssl警告的代码与https服务进行通信,则必须在服务点管理器上设置证书验证器以绕过它以进行测试。

    1
    ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, errors) => true;

    我还没有完全实现它,但是该网站似乎为设置证书和代码提供了很好的演练。


    这是不使用httpcfg.exe(XP)或netsh.exe(Vista +)将SSL证书绑定到IP / PORT组合的另一种方法。

    http://dotnetcodebox.blogspot.com.au/2012/01/how-to-work-with-ssl-certificate.html

    要点是,您可以使用Windows内置的C ++ HttpSetServiceConfiguration API以编程方式(而不是通过命令行)来执行此操作,从而消除了对操作系统的依赖并安装了httpcfg。


    类文档

    有这个注意事项:

    If you create an HttpListener using
    https, you must select a Server
    Certificate for that listener.
    Otherwise, an HttpWebRequest query of
    this HttpListener will fail with an
    unexpected close of the connection.

    还有这个:

    You can configure Server Certificates
    and other listener options by using
    HttpCfg.exe. See
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/http/http/httpcfg_exe.asp
    for more details. The executable is
    shipped with Windows Server 2003, or
    can be built from source code
    available in the Platform SDK.

    第二个解释了第一个音符吗?如问题所述,我使用httpcfg.exe将证书绑定到特定端口。如果他们打算除此以外的其他用途,则说明不明确。


    我遇到了与您相同的问题。幸运的是,在搜索了本页上所有困难的步骤之后,使SSL与我的HttpListener一起使用。


    推荐阅读