2016-07-08 56 views
4

最終的にはIoT向けのUWPアプリをC#で作成していますが、今はローカルでのみデバッグしています。私もWindows.Web.Http.HttpClientを使用して、私が書いた自己ホストWCF REST Webサービスに接続し、テストのために同じマシン上でコンソールアプリケーションとして実行しています。サービスは証明書との相互認証を必要とするため、私はCA証明書、サービス証明書、およびクライアント証明書を持っています。UWPアプリHttpClient HTTPSクライアント証明書の問題

私のUWPのコードは次のように動作します。クライアント証明書とCA証明書のための

  1. チェックアプリの証明書ストアにインストールされています。
  2. PFXファイルとCERファイルからそれぞれインストールします。
  3. HttpBaseProtocolFilterCertificateを取り付けて、私は次のエラーを取得するPostAsync呼び出した後HttpClient
  4. コールHttpClient.PostAsync

にフィルタを追加します。An Error Occurred in the Secure Channel Supportを。オンラインでの検索や常識的な検索の結果、HttpClientは相互認証されたSSL接続の確立に問題があるため、バーフリーになっています。しかし私のトラブルシューティングに基づいて、私は理由を理解できません。

また、私はSystem.Net.Http.HttpClientを使用してプレーンな古いコンソールアプリケーションを作成しました。要求にクライアント証明書が添付されていて、すべて正常に機能します。残念ながら、System.NetはUWPで完全にサポートされていません。また、UWP HttpClientに証明書を添付しないようにしました。インストールされた証明書を選択するためのUIが表示されます。正しい証明書を選択しても、同じ例外が発生します(これは、証明書が正しくインストールされ、アプリケーションの観点からCAと正しく検証されていることを少なくとも私に知らせます)。追加で、私はブラウザからWebサービスのGETを打ち、プロンプトが表示されたらクライアント証明書を選択し、ファイルをダウンロードできるようになりました。

私はFiddlerを使用しようとしましたが、トラフィックをプロキシする方法があると思われます。私のWebサービスが禁止されているリクエストを拒否することを除いて、もう少しうまくいくように見えます(おそらくFiddlerは正しいクライアント要求の中の証明書)。 WiresharkをWindows上でlocalhostを使って動作させるのは苦痛なので、私はまだWiresharkにヒットしていません。

私の次のステップは、クライアント認証を必要としないようにWebサービスを変更し、それが問題かどうかを確認することです。

2つの質問:この場合、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ランタイムクラスを見ると、証明書秘密鍵へのアクセスを明示的に要求する方法が見つからないため、アプリケーション開発者は何をするべきですか?

解決策は、選択された証明書を使用して小さなデータを「署名」することです。アプリケーションがCryptographicEngine.SignAsyncを呼び出すと、基になるコードは秘密鍵へのアクセスを要求して署名を行い、アプリケーションが証明書の秘密鍵にアクセスできるようにするかどうかを尋ねられます。同期バージョンの関数Sign:は、確認ダイアログの表示をブロックするオプションを使用するため、この関数の 'Async'バージョンを呼び出す必要があります。例えば

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. ウルプロジェクトの使用中のフリストサービスコールは、次のコードは、ほとんどのある証明書の検証を無視するには明らかに証明書をファイルに追加ファイルを追加しますログイン機能に適しています。

は {

  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(); 
     } 
関連する問題