Подтвердить что ты не робот

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

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

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

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

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

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

Редактировать:
Шаги, предпринятые до сих пор

  • Создан работающий HTTPListener в С#, который работает для 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, который мне не хватает (имеется в виду, что в С# мне нужно сделать больше, чем просто добавить префикс к слушателю, указывающий на HTTPS, что я и сделал)
  • Вы где-то пропустили этап настройки?
  • Что еще я могу сделать, чтобы проанализировать проблему?
  • Является ли сообщение об ошибке в журнале системных событий признаком проблемы? Если так, то как бы это исправить?
4b9b3361

Ответ 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 в следующей команде:

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

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;

Ответ 2

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


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

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

Ответ 4

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

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

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

Ответ 5

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

имеет следующее примечание:

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

Первая заметка объясняется второй? Как указано в вопросе, я использовал httpcfg.exe для привязки сертификата к определенному порту. Если они намереваются что-то другое, примечание неоднозначно.

Ответ 6

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