【问题标题】:Using C# can I make an SSL connection using Server Name Indication (SNI)?使用 C# 可以使用服务器名称指示 (SNI) 建立 SSL 连接吗?
【发布时间】:2012-03-30 15:23:46
【问题描述】:

我目前拥有与服务器建立 SSL 连接的代码:

using (client = new TcpClient())
{

    client.Connect(Hostname, Port);
    var callback = new RemoteCertificateValidationCallback(ValidateServerCertificate);


    using (stream = new SslStream(client.GetStream(), false, callback))
    {
        stream.AuthenticateAsClient(Hostname);
    }
}

但是,我认为它不支持 SNI,因为从 SNI 配置的服务器返回了错误的证书。有没有办法使用 SNI 建立 SSL 连接?

我正在使用 .NET 2(如有必要愿意升级)。我使用的是 Windows 7,但如果可能的话,我希望该软件能够在其他平台上运行,例如 Windows 2008。

【问题讨论】:

标签: c# ssl sni


【解决方案1】:

因此得出结论,答案似乎是:不,您无法使 TLS 连接使用 SNI :-(

我找不到任何与 SNI 建立 TLS 连接的 C# 示例代码。不过理论上,应该可以手动创建,即按照How to implement Server Name Indication (SNI)

但是,这里的尝试失败了:TLS SNI with C#

【讨论】:

    【解决方案2】:

    答案似乎是“是”,因为有一个支持 SNI 的 C# 实现。 This bug report 提到支持带有 SNI 的 HTTPS 请求的 mono 版本。

    【讨论】:

      【解决方案3】:

      我们在尝试使用双向 SSL 连接到业务 API 时遇到了类似的问题。标准 .NET 库不起作用。您可以使用第三方库http://curl.haxx.se/libcurl/ 作为可能的解决方案之一。

      libcurl 是一个免费且易于使用的客户端 URL 传输库,支持 DICT、FILE、FTP、FTPS、Gopher、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、POP3、POP3S、 RTMP、RTSP、SCP、SFTP、SMTP、SMTPS、Telnet 和 TFTP。 libcurl 支持 SSL 证书、HTTP POST、HTTP PUT、FTP 上传、基于 HTTP 表单的上传、代理、cookie、用户+密码身份验证(Basic、Digest、NTLM、Negotiate、Kerberos)、文件传输恢复、http 代理隧道等。

      .NET库可以从http://sourceforge.net/projects/libcurl-net/上传

      当你上传它时,将 libcurl.dll 更改为你能找到的最新版本(它应该是 7.18.1 或更高版本)。在当前的 libcurl-nel 包中,它比需要的要旧。

       public string HTTPGet(string URL, string Proxy, string certName = null, string certPassword = null)
       {
          Easy easy = new Easy();
          SockBuff = "";
          try
          {
              Easy.WriteFunction wf = new Easy.WriteFunction(OnWriteData);
              easy.SetOpt(CURLoption.CURLOPT_URL, URL);
              easy.SetOpt(CURLoption.CURLOPT_TIMEOUT, "60");
              easy.SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, wf);
              easy.SetOpt(CURLoption.CURLOPT_USERAGENT, UserAgent);
              easy.SetOpt(CURLoption.CURLOPT_COOKIEFILE, CookieFile);
              easy.SetOpt(CURLoption.CURLOPT_COOKIEJAR, CookieFile);
              easy.SetOpt(CURLoption.CURLOPT_FOLLOWLOCATION, true);
      
              if (!string.IsNullOrEmpty(certName))
              {
                  easy.SetOpt(CURLoption.CURLOPT_SSLCERT, certName);
                  if (!string.IsNullOrEmpty(certPassword))
                  {
                      easy.SetOpt(CURLoption.CURLOPT_SSLCERTPASSWD, certPassword);
                  }
              }
      
              if (URL.Contains("https"))
              {
                  easy.SetOpt(CURLoption.CURLOPT_SSL_VERIFYHOST, 1);
                  easy.SetOpt(CURLoption.CURLOPT_SSL_VERIFYPEER, 0);
              }
      
              if (!string.IsNullOrEmpty(Proxy))
              {
                  easy.SetOpt(CURLoption.CURLOPT_PROXY, Proxy);
                  easy.SetOpt(CURLoption.CURLOPT_PROXYTYPE, CURLproxyType.CURLPROXY_HTTP);
              }
      
              var code = easy.Perform();
              easy.Cleanup();
              Console.WriteLine(code);
          }
          catch
          {
              Console.WriteLine("Get Request Error");
          }
      
          return SockBuff;
      }
      
      public static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb, Object extraData)
      {
          // Console.Write(System.Text.Encoding.UTF8.GetString(buf));
          SockBuff = SockBuff + System.Text.Encoding.UTF8.GetString(buf);
      
          return size * nmemb;
      }
      

      【讨论】:

        【解决方案4】:

        我知道这是一篇较旧的帖子,但我最近需要同样的东西。我有一个 C# 应用程序,用于在 C# 中动态创建网站。我需要站点的绑定在创建时设置“服务器名称指示”标志,因为我们试图在同一个 IP 地址上使用多个 SSL 站点。

        事实证明,您现在可以在 C# 中执行此操作。您可以传递一个标志选项,该选项将打开 SNI 选项。我希望这可以帮助任何有这个问题的人。这是一个例子:

        // Create site using server manager
        ServerManager sm = new ServerManager();
        Site mySite =  sm.Sites.Add("example.com", "C:\Test Website\", 443);
        
        // Creating binding object to store SSL cert
        var ibind = mySite.Bindings.CreateElement();
        ibind.Protocol = "https";
        ibind.BindingInformation = "*:443:" + domain;
        ibind.CertificateHash = certificate.GetCertHash();
        
        // This option will turn on SNI (server name indication)
        ibind.SetAttributeValue("sslFlags", 1);
        
        // Add the binding to the site
        mySite.Bindings.Add(ibind);

        【讨论】:

        • OP 要求提供客户端解决方案,而不是服务器端。
        猜你喜欢
        • 2012-10-08
        • 1970-01-01
        • 2017-05-23
        • 2012-09-03
        • 2014-01-20
        • 2011-07-04
        • 1970-01-01
        • 2020-05-08
        相关资源
        最近更新 更多