2016-07-08 8 views
4

Я пишу приложение UWP на C#, которое в конечном итоге предназначено для IoT, но сейчас я только отлаживаю локально. Я использую Windows.Web.Http.HttpClient для подключения к самообслуживаемому веб-сервису WCF REST, который я также написал и работает как консольное приложение на той же машине для тестирования. Служба требует взаимной аутентификации с сертификатами, поэтому у меня есть сертификат CA, сертификат службы и клиентский сертификат.UWP-приложение HttpClient HTTPS-клиентские проблемы с сертификатом

Мой UWP код работает так:

  1. Проверьте магазин приложений сертификат для клиента CERT и CA серт установлен.
  2. Если нет, установите из файла PFX и файла CER, соответственно.
  3. Прикрепите Certificate к HttpBaseProtocolFilter и добавить фильтр к HttpClient
  4. Вызвать HttpClient.PostAsync

После того как я называю PostAsync я получаю следующее сообщение об ошибке: An Error Occurred in the Secure Channel Support. После многократного поиска в Интернете и по здравому смыслу, я уверен, что HttpClient является барфинг из-за проблемы с установлением взаимно аутентифицированного SSL-соединения. Но на основании моего устранения неполадок я не могу понять, почему.

Чтобы решить проблему, я написал обычное старое приложение консоли с помощью System.Net.Http.HttpClient, приложил сертификат клиента к запросу и все отлично работает. К сожалению, System.Net не полностью поддерживается в UWP. Я также попробовал НЕ прикреплять сертификат к UWP HttpClient, и приложение запрашивает у меня пользовательский интерфейс для выбора установленного сертификата. Я выбираю правильный сертификат и все равно получаю такое же исключение (это, по крайней мере, позволяет мне знать, что сертификат установлен правильно и корректно проверяется с помощью CA с точки зрения приложения). В дополнение, я ударил GET на веб-службе из браузера, выберем сертификат клиента при появлении запроса и могу загрузить файл.

Я попытался использовать Fiddler, и, полагаю, из-за того, как он проксирует трафик, он, похоже, работает немного дальше, за исключением того, что мой веб-сервис отклоняет запрос как Запретный (предположительно потому, что Fiddler не включает правильный клиент сертификат в запросе). Я еще не попал в Wireshark, потому что это боль, чтобы заставить Wireshark работать с использованием localhost в Windows.

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

Два вопроса: Почему Windows.Web.Http.HttClient не работает в этом случае? И, что менее важно, какие-либо рекомендации относительно хороших инструментов мониторинга HTTP, чтобы помочь мне отладить это дальше?

+0

эти самоподписывающиеся сертификаты? –

+0

Я использовал 'makecert' для создания сертификата CA, и из этого сертификата CA выдан сертификат клиента и сервиса с помощью' makecert'. – koopaking3

+0

Возможно уместно: https://code.msdn.microsoft.com/windowsapps/How-to-ignore-Self-Signed-e50b89b6 –

ответ

3

У этого сообщения MSDN появился ответ. Кажется, что надзор над частью MS требует отдельного бессмысленного вызова API заблаговременно. Ну что ж.

http://blogs.msdn.com/b/wsdevsol/archive/2015/03/26/how-to-use-a-shared-user-certificate-for-https-authentication-in-an-enterprise-application.aspx

Выдержка из статьи:

Однако подсистема безопасности требует подтверждения пользователя, прежде чем разрешить доступ к сертификатов закрытого ключа сертификата хранится в разделяемой сертификатов пользователя магазина. Чтобы усложнить ситуацию, если сертификат клиента указан в коде, то сетевые функции нижнего уровня предполагают, что приложение уже позаботилось об этом и не будет запрашивать подтверждение пользователя.

Если вы посмотрите классы Windows Runtime, связанные с сертификатами, вы не найдете какой-либо метод для явного запроса доступа к закрытому ключу сертификата, так что же делать разработчику приложения?

Решение заключается в использовании выбранного сертификата для «Подписи» небольшого количества данных. Когда приложение вызывает CryptographicEngine.SignAsync, базовый код запрашивает доступ к закрытому ключу, чтобы выполнить подписание, в этот момент пользователю предлагается, разрешить ли приложение доступ к закрытому ключу сертификата. Обратите внимание, что вы должны вызывать версию Async этой функции, потому что синхронная версия функции: Sign, использует параметр, который блокирует отображение диалогового окна подтверждения.

Например:

public static async Task<bool> VerifyCertificateKeyAccess(Certificate selectedCertificate) 
{ 
    bool VerifyResult = false; // default to access failure 
    CryptographicKey keyPair = await PersistedKeyProvider.OpenKeyPairFromCertificateAsync(
             selectedCertificate, HashAlgorithmNames.Sha1, 
             CryptographicPadding.RsaPkcs1V15); 
    String buffer = "Data to sign"; 
    IBuffer Data = CryptographicBuffer.ConvertStringToBinary(buffer, BinaryStringEncoding.Utf16BE); 

    try 
    { 
     //sign the data by using the key 
     IBuffer Signed = await CryptographicEngine.SignAsync(keyPair, Data); 
     VerifyResult = CryptographicEngine.VerifySignature(keyPair, Data, Signed); 
    } 
    catch (Exception exp) 
    { 
     System.Diagnostics.Debug.WriteLine("Verification Failed. Exception Occurred : {0}", exp.Message); 
     // default result is false so drop through to exit. 
    } 

    return VerifyResult; 
} 

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

0
  1. Добавить сертификат файл вашего проекта
  2. Добавить сертификат в проявленной файл (дать путь к файлу в приложении)
  3. Фрист служба Зов в использовании Ur проекта игнорировать проверку сертификата следующего код наиболее Подходит для функции входа.

попробовать {

  var filter = new HttpBaseProtocolFilter(); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationInformationMissing); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain); 

      Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient(filter); 
      TimeSpan span = new TimeSpan(0, 0, 60); 
      var cts = new CancellationTokenSource(); 
      cts.CancelAfter(span); 
      var request = new Windows.Web.Http.HttpRequestMessage() 
      { 
       RequestUri = new Uri(App.URL + "/oauth/token"), 
       Method = Windows.Web.Http.HttpMethod.Post, 
      }; 
      //request.Properties. = span; 
      string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(Server_Username + ":" + Server_Password)); 
      var values = new Dictionary<string, string> 
       { { "grant_type", "password" },{ "username", Uname}, { "password", Pwd }}; 
      var content = new HttpFormUrlEncodedContent(values); 
      request.Headers.Add("Authorization", "Basic " + encoded); 
      request.Content = content; 
      User root = new User(); 
      using (Windows.Web.Http.HttpResponseMessage response = await client.SendRequestAsync(request).AsTask(cts.Token)) 
      { 
       HttpStatusCode = (int)response.StatusCode; 
       if (HttpStatusCode == (int)HttpCode.OK) 
       { 
        using (IHttpContent content1 = response.Content) 
        { 
         var jsonString = await content1.ReadAsStringAsync(); 
         root = JsonConvert.DeserializeObject<User>(jsonString); 
         App.localSettings.Values["access_token"] = root.Access_token; 
         App.localSettings.Values["refresh_token"] = root.Refresh_token; 
         App.localSettings.Values["expires_in"] = root.Expires_in; 
         var json = JsonConvert.SerializeObject(root.Locations); 
         App.localSettings.Values["LocationList"] = json; 
         App.localSettings.Values["LoginUser"] = Uname; 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      ex.ToString(); 
     } 

 Смежные вопросы

  • Нет связанных вопросов^_^