2009-05-21 19 views
9

私は以前の投稿で間違った質問をしていました。私は安全なWebサイト(https://..)として動作しているX.509証明書でセキュリティ保護されたWebサービスを持っています。会社のルートCAが発行したクライアントのマシン証明書(X.509)を使用して、クライアントマシンがサービスを使用することが許可されていることをサーバーに確認します。これを行うためには、私は証明書を検査し、特定の特徴を探し、その値をデータベースに格納された値(サムプリント?)と照合する必要があります。ここで WebサービスでクライアントからX509Certificateを送信するにはどうすればよいですか?

は( http://msdn.microsoft.com/en-us/magazine/cc163454.aspxからまっすぐ持ち上げた)私は、ローカル証明書ストアから証明書を取得するために使用するコードです:

public static class SecurityCertificate 
{ 
    private static X509Certificate2 _certificate = null; 

    public static X509Certificate2 Certificate 
    { 
     get { return _certificate; } 
    } 

    public static bool LoadCertificate() 
    { 
     // get thumbprint from app.config 
     string thumbPrint = Properties.Settings.Default.Thumbprint; 
     if (string.IsNullOrEmpty(thumbPrint)) 
     { 
      // if no thumbprint on file, user must select certificate to use 
      _certificate = PickCertificate(StoreLocation.LocalMachine, StoreName.My); 
      if (null != _certificate) 
      { 
       // show certificate details dialog 
       X509Certificate2UI.DisplayCertificate(_certificate); 
       Properties.Settings.Default.Thumbprint = _certificate.Thumbprint; 
       Properties.Settings.Default.Save(); 
      } 
     } 
     else 
     { 
      _certificate = FindCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, thumbPrint); 
     } 

     if (null == _certificate) 
     { 
      MessageBox.Show("You must have a valid machine certificate to use STS."); 
      return false; 
     } 

     return true; 
    } 

    private static X509Certificate2 PickCertificate(StoreLocation location, StoreName name) 
    { 
     X509Store store = new X509Store(name, location); 
     try 
     { 
      // create and open store for read-only access 
      store.Open(OpenFlags.ReadOnly); 

      X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByIssuerName, STSClientConstants.NBCCA, true); 
      if (0 == coll.Count) 
      { 
       MessageBox.Show("No valid machine certificate found - please contact tech support."); 
       return null; 
      } 

      // pick a certificate from the store 
      coll = null; 
      while (null == coll || 0 == coll.Count) 
      { 
       coll = X509Certificate2UI.SelectFromCollection(
         store.Certificates, "Local Machine Certificates", 
         "Select one", X509SelectionFlag.SingleSelection); 
      } 

      // return first certificate found 
      return coll[ 0 ]; 
     } 
     // always close the store 
     finally { store.Close(); } 
    } 

    private static X509Certificate2 FindCertificate(StoreLocation location, StoreName name, X509FindType findType, string findValue) 
    { 
     X509Store store = new X509Store(name, location); 
     try 
     { 
      // create and open store for read-only access 
      store.Open(OpenFlags.ReadOnly); 

      // search store 
      X509Certificate2Collection col = store.Certificates.Find(findType, findValue, true); 

      // return first certificate found 
      return col[ 0 ]; 
     } 
     // always close the store 
     finally { store.Close(); } 
    } 

その後、私は以下のようなものを発信ストリームに証明書を添付:

public static class ServiceDataAccess 
{  
    private static STSWebService _stsWebService = new STSWebService(); 

    public static DataSet GetData(Dictionary<string,string> DictParam, string action) 
    { 
     // add the machine certificate here, the first web service call made by the program (only called once) 
     _stsWebService.ClientCertificates.Add(SecurityCertificate.Certificate); 
     // rest of web service call here... 
    } 
} 

私の質問はこれです - どのようにWebサービスコードの証明書を "取得"するのですか?私がカスタム検証を行う方法をカバーしているほとんどのサンプルコードスニペットは、そこにGetCertificate()コールがあります。

メインクラスはWebServiceを継承しているので、Context.Request.ClientCertificateを使用して証明書を取得できますが、これはX509Certificate2で​​はなくHttpClientCertificateです。 HttpContextは私に同じ結果を与えます。他のアプローチはすべて、Webコンフィグレーションコードを使用して事前定義された検証コードを呼び出しますが、カスタムC#メソッドを呼び出して検証を行う方法のヒントはありません。

誰かが戻ってきて「見て、ちょうどこれをやって、うまくいく」という別の「愚かな質問」だと確信していますが、それでも問題ありません。私はこれを働かせるために何時間も費やしてきましたが、私の誇りは現時点ではほとんど存在しません。誰かが私の方法の誤りを私に見せてくれる?

おかげで、 デイブ

+0

HttpContextをお持ちでない場合は、http:// stackoverflowの回答を参照してください。com/questions/7528455/how-to-get-the-x509certificate-from-a-client-request?lq = 1 –

答えて

12

を参照してください。

X509Certificate2 cert = new X509Certificate2(Context.Request.ClientCertificate.Certificate); 
+0

それは動作します!私は最終的に私の問題の肉体に慣れることができます。データベースの記憶値と一致させるためにどのような価値があるのか​​を考えてみましょう... ありがとう!! – DaveN59

+1

データベースを信頼できる機関として扱っている場合は、サムプリントを使っても問題ありません。私はこのアプローチを採用したアプリケーションを開発しました。 OTOHでは、(CAを使用して)分散トラストモデルが必要な場合、追加のチェックを行う必要があります(証明書チェーンの検証など)。 – DSO

+0

私はあまりにも早く行動したかもしれないと思います。 Thumbprintにアクセスしようとすると「System.Security.Cryptography.CryptographicException」例外がスローされます。つまり、http証明書がX509Certificate2タイプであっても、実際にクライアントから送信された証明書と同じか、新しいそれだけのように見える獣? – DaveN59

1

あなたはServicePointManager.ServerCertificateValidationCallbackに自分をフック私はそのしばらくして、類似した何かを思い出しますが、あなたのWebサービスでこれを試してみましたhttp://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx

+0

これにはいくつかの参照があります。これにより、クライアント証明書ではなくサーバー証明書が検証されます。 – DaveN59

1

証明書をユーザーに戻す方法については、証明書が信頼されたルートに戻って検証されているため、そのキーに関連付けられたユーザーのIDが良好であり、b取り消された場合)、証明書で要求されたIDをユーザーに結びつける必要があります。主題DNのLDAP文字列形式を使用して、それを調べて(cn = Username、ou = Department ...)ローカルIDを特定することができます。これは、カードが失われたり、証明書が自然に期限切れになったために、ユーザーが鍵/証明書を再生成した場合には復元力があります。これは、2人のCAが2人の異なる人物に同じ主題名を持つ2つの証明書を発行しないという事実に依存する。

証明書がMS CAによって発行された場合、実際にドメインログオン名であるUPNが含まれている可能性があります。

また、ユーザーの身元を実際の証明書に結びつける場合は、通常、発行者名と証明書のシリアル番号を格納する方法があります。 CAは、証明書ごとに固有のシリアル番号を発行する必要があります。シリアル番号は、CAによって大きくなる場合があります。ただし、この方法を使用すると、ユーザー証明書が再発行されるたびにデータベースの証明書の詳細を更新する必要があります。

+1

優れた情報!私がまだプロジェクトに取り組んでいれば、これはちょうど私が最初の実装で作成した問題を解決するために必要な情報の種類です。 しかし、私は別の責任を持つ別の会社に移動したので、他の人のための練習として残しておきます... フィードバックありがとうございます! – DaveN59

関連する問題