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

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

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

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

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

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

Edit:
Шаги, предпринятые до сих пор

  • Создан работающий 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 ]

9 голосов
/ 08 апреля 2009

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

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

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

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;
7 голосов
/ 29 сентября 2012

Вам просто нужно привязать сертификат к порту 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;
6 голосов
/ 07 августа 2008

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

4 голосов
/ 02 марта 2015

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

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

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

3 голосов
/ 08 августа 2008

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

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

Если вы создаете 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 для привязки сертификата к определенному порту. Если они намереваются что-то иное, примечание неоднозначное.

2 голосов
/ 28 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...