Как добавить SSL в приложение .net, которое использует httplistener - оно не будет работать на IIS

Последние изменения, выделенные жирным шрифтом, я использую HttpListenerкласс .net , но я не буду запускать это приложение на IIS и не использую ASP.net. Этот веб-сайт описывает, какой код на самом деле использовать для реализации SSL с asp.net, а этот сайт описывает, как настроить сертификаты (хотя я не уверен, работает ли он только для IIS или нет).

Документация класса описывает различные типы аутентификации (базовая, дайджест, Windows и т. Д.) - ни один из них не относится к SSL. Это говорит о том, что если используется HTTPS, вам нужно будет установить сертификат сервера . Будет ли это однострочное свойство, а HttpListenerостальные?

Короче говоря, мне нужно знать, как настроить сертификаты и как изменить код для реализации SSL.

Хотя это не происходит, когда я пытаюсь получить доступ к HTTPS, я заметил ошибку в моем журнале системных событий - источником является «Schannel», а содержание сообщения:

Произошла неустранимая ошибка при попытке доступа к закрытому ключу учетных данных сервера SSL. Код ошибки, возвращаемый криптографическим модулем, - 0x80090016.

Изменить:
шаги, предпринятые до сих пор

  • Создан работающий HTTPListener в C #, который работает для HTTP-соединений (например, « http: // localhost: 8089 / foldername / »
  • Создан сертификат с использованием makecert.exe
  • Добавлен сертификат, которому можно доверять, используя certmgr.exe
  • Использовал Httpcfg.exe для прослушивания SSL-соединений на тестовом порту (например, 8090)
  • Добавлен порт 8080 в HTTPListener через listener.Prefixes.Add ( https: // localhost: 8090 / foldername / ");
  • проверил 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, что я и сделал)
  • Вы где-то пропустили этап настройки?
  • Что еще я могу сделать, чтобы проанализировать проблему?
  • Является ли сообщение об ошибке в журнале системных событий признаком проблемы? Если так, то как бы это исправить?
6.08.2008 21:18:47
6 ОТВЕТОВ

Я еще не полностью его реализовал, но этот веб-сайт, кажется, дает хорошее представление о настройке сертификатов и кода.

6
6.08.2008 22:29:57

Документация класса

имеет это примечание:

Если вы создаете HttpListener с помощью https, вы должны выбрать сертификат сервера для этого прослушивателя. В противном случае запрос HttpWebRequest этого HttpListener завершится неудачно с неожиданным закрытием соединения.

и это:

Вы можете настроить сертификаты сервера и другие параметры прослушивателя с помощью 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
8.08.2008 16:37:29

Я столкнулся с той же проблемой, что и вы. К счастью, после непростых шагов на этой странице заставьте SSL работать с моим HttpListener.

2
29.04.2014 06:01:33

У меня похожая проблема, и кажется, что может быть проблема с самим сертификатом.

Вот путь, который работал для меня:

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

затем найдите отпечаток сертификата , скопируйте его в буфер обмена и удалите пробелы. Это будет параметр после -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 истечет время ожидания, как будто отпечаток большого пальца никогда не был зарегистрирован. Если кто знает почему - плз комментируйте

РЕДАКТИРОВАТЬ1 : После некоторой игры, я нашел инициализацию для 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;
10
7.02.2016 17:38:45

Вам просто нужно привязать сертификат к порту 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}

Если вы хотите создать самоподписанный сертификат, чтобы проверить это,

  1. Откройте IIS
  2. Нажмите на имя вашего компьютера
  3. Нажмите значок сертификаты сервера
  4. Нажмите создать самоподписанный сертификат
  5. Дважды щелкните и перейдите к деталям
  6. Там вы увидите отпечаток, просто удалите пробелы.

    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.


Также очень важно, чтобы, если вы связываетесь со службой https из кода с предупреждением ssl, вы должны настроить средство проверки сертификатов в диспетчере точек обслуживания, чтобы обойти его в целях тестирования.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, errors) => true;
7
7.02.2016 17:39:09

Вот альтернативный способ привязать сертификат SSL к комбинации IP / PORT без использования httpcfg.exe(XP) или netsh.exe(Vista +).

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

Суть его в том, что вы можете использовать встроенный в Windows API-интерфейс HttpSetServiceConfiguration C ++, чтобы делать это программно, а не через командную строку, следовательно, удаляя зависимость от ОС и устанавливая httpcfg.

4
2.03.2015 05:14:45
Я опубликовал этот код в виде пакета Nuget . Не стесняйтесь использовать его.
Serghei Gorodetki 4.06.2015 12:55:53