С помощью С# я могу сделать SSL-соединение с помощью Server Name Indicication (SNI)?

В настоящее время у меня есть этот код, который делает 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. Есть ли способ сделать SSL-соединение с использованием SNI?

Я использую .NET 2 (желаю обновить, если необходимо). Я использую Windows 7, но хотел бы, чтобы программное обеспечение работало на других платформах, таких как Windows 2008, если это возможно.

Ответ 1

Итак, в заключение кажется, что ответ: Нет, вы не можете использовать SNMP-соединение для использования SNI: - (

Я не смог найти код примера С#, создающий TLS-соединение с SNI. Теоретически, однако, должно быть возможно создать это вручную, т.е. Согласно Как реализовать идентификацию имени сервера (SNI)

однако попытка здесь потерпела неудачу: TLS SNI с С#

Ответ 2

Ответ кажется "да", так как существует реализация С#, которая поддерживает SNI. В этом отчете об ошибке упоминается версия mono, которая поддерживает HTTPS-запросы с SNI.

Ответ 3

Мы столкнулись с подобной проблемой, пытаясь подключиться к бизнес-API, используя общий SSL. Стандартные библиотеки .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

Я знаю, что это более старая должность, но мне недавно нужно было то же самое. У меня есть приложение на С#, которое я использовал для динамического создания сайтов на С#. Мне нужно, чтобы привязки сайтов устанавливали флаг "имя сервера" при создании, потому что мы пытаемся использовать несколько сайтов SSL на одном и том же IP-адресе.

Как оказалось, теперь вы можете сделать это на С#. Вы можете передать флаг, который включит опцию 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);