首页 文章

如何将SSL添加到使用httplistener的.net应用程序 - 它将*不会在IIS上运行

提问于
浏览
38

Most recent edits in bold 我正在使用.net HttpListener 类,但我在IIS上运行并且没有使用ASP.net . 这个web site描述了用asp.net实现SSL的实际代码,this site描述了如何设置证书(虽然我不确定它是否只适用于IIS) .

类文档描述了各种类型的身份验证(基本,摘要,Windows等)---它们都没有引用SSL . 它确实说如果HTTPS is used, you will need to set a server certificate . 这将是一行属性设置, HttpListener 算出其余的?

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

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

尝试访问SSL服务器凭据私钥时发生致命错误 . 加密模块返回的错误代码是0x80090016 .

编辑:
Steps taken so far

  • 在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/ ") in a browser and receive "数据传输中断“(在Firefox中)
    Visual Studio中的

  • 调试显示,当HTTPS连接启动时,接收请求的侦听器回调永远不会被命中 - 我没有看到任何可以设置断点以更早捕获其他内容的地方 .

  • netstat显示侦听端口对HTTPS和HTTP都是开放的 . 尝试连接后,HTTPS端口会转到TIME_WAIT .

  • Fiddler and HTTPAnalyzer don't catch any of the traffic, I guess it doesn't get far enough in the process to show up in those HTTP analysis tools

Questions

  • 问题是什么?

  • 是否有一段我缺少的.Net代码(这意味着我必须在C#中做更多的事情,而不是简单地向侦听器添加一个指向HTTPS的前缀,这就是我所做的)

  • 错过了某处的配置步骤?

  • 我还可以做些什么来分析问题?

  • 系统事件日志中的错误消息是否是问题的标志?如果是这样,它将如何修复?

6 回答

  • 2

    我有类似的问题,似乎证书本身可能存在问题 .

    这是对我有用的路径:

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

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

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

    然后在https://localhost:801/上运行一个服务主机,它运行正常 .

    我无法工作的是https在自生成的证书上运行 . 这是我运行的代码生成一个代码(为清楚起见,错误处理):

    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的初始化,它生成了适当的证书:

    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;
    
  • 9

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

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

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

    如果要创建自签名证书来测试它,

    • 打开IIS

    • 单击您的计算机名称

    • 单击“服务器证书”图标

    • 单击“生成自签名证书”

    • 双击并转到详细信息

    • 您将在那里看到指纹,只需删除空格即可 .

    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服务进行通信,则必须在服务点管理器上设置证书验证器以绕过它以进行测试,这一点也非常重要 .

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

    我还没有完全实现它,但这个网站似乎给了good walkthrough设置证书和代码 .

  • 4

    以下是在不使用 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 .

  • 6

    class documentation

    有这个说明:

    如果使用https创建HttpListener,则必须为该侦听器选择服务器证书 . 否则,此HttpListener的HttpWebRequest查询将因意外关闭连接而失败 .

    还有这个:

    您可以使用HttpCfg.exe配置服务器证书和其他侦听器选项 . 有关详细信息,请参阅http://msdn.microsoft.com/library/default.asp?url=/library/en-us/http/http/httpcfg_exe.asp . 可执行文件随Windows Server 2003一起提供,或者可以从Platform SDK中提供的源代码构建 .

    是第二个解释的第一个注释吗?如问题中所述,我使用httpcfg.exe将证书绑定到特定端口 . 如果他们想要除此之外的其他内容,则该注释含糊不清 .

  • 3

    我遇到了和你一样的问题 . 幸运的是,在搜索this page上的硬步骤后,使SSL与我的HttpListener一起工作 .

相关问题