2009-10-29 33 views
11

クライアント証明書を使用してWebServiceに対して自分自身を認証しようとしていますが、何らかの理由で説明しますが、ストアから証明書を読み込むのではなく、 。証明書ストアにクライアント証明書を使用していません

// gw is teh WebService client 
X509Certificate cert = new X509Certificate(PathToCertificate); 
_gw.ClientCertificates.Add(ClientCertificate()); 
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true; 
_gw.DoSomeCall(); 

戻り常に403 - サービスが私を許可していません。しかし、その証明書をCertStoreに保存すると、その証明書が機能します。 (MSDNに記載されているように)

証明書は店頭で使用できますか?

(理由は、私は時々、Webサービス(サーバー)を呼び出すWindowsサービス(クライアント)を得たこと、であり、時間の不定量の後にサービスが明白な理由なしに、自分の証明書とdoesntのは、サーバーに対して認可「忘れ」)

答えて

22

PathToCertificateはどのような種類のファイルですか? .cerファイルの場合、証明書の秘密鍵は含まれず、SSL/TLS用にその証明書を使用しようとすると失敗します。

ただし、証明書の公開鍵と秘密鍵を含むPKCS7またはPKCS12ファイルがある場合は、コードが機能します(秘密鍵にパスワードがある場合はパスワードを使用する必要があります)。

これをテストするには、http://www.mono-project.com/UsingClientCertificatesWithXSPに行き、その指示に従ってclient.p12ファイルを作成しました。また、テスト用にHttpListenerを使用した単純なHTTPSサーバーを作成しました。

その後、私は「クライアント。」内に次のプログラムをコンパイルして実行しますように:

client.p12は前に生成されたPKCS12ファイルであると「パスワード」は、私がプライベートキーに設定されたパスワードです
client.exe https://<MYSSLSERVER>/ client.p12 password 

証明書の

using System; 
using System.IO; 
using System.Net; 
using System.Security.Cryptography.X509Certificates; 
using System.Text; 

public class HttpWebRequestClientCertificateTest : ICertificatePolicy { 

    public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate, 
      WebRequest request, int error) 
    { 
      return true; // server certificate's CA is not known to windows. 
    } 

    static void Main (string[] args) 
    { 
      string host = "https://localhost:1234/"; 
      if (args.Length > 0) 
        host = args[0]; 

      X509Certificate2 certificate = null; 
      if (args.Length > 1) { 
        string password = null; 
        if (args.Length > 2) 
          password = args [2]; 
        certificate = new X509Certificate2 (args[1], password); 
      } 

      ServicePointManager.CertificatePolicy = new HttpWebRequestClientCertificateTest(); 

      HttpWebRequest req = (HttpWebRequest) WebRequest.Create (host); 
      if (certificate != null) 
        req.ClientCertificates.Add (certificate); 

      WebResponse resp = req.GetResponse(); 
      Stream stream = resp.GetResponseStream(); 
      StreamReader sr = new StreamReader (stream, Encoding.UTF8); 
      Console.WriteLine (sr.ReadToEnd()); 
    } 
} 

サーバーコードとテストの両面で使用される証明書をアップロードしたい場合はお知らせください。

+0

は、Windows .NET上で同じ仕事を作る方法を知っていますか?何らかの理由でx509ストア – galets

1

証明書のパスワードが必要ですか?その場合、コンストラクタにフィールドがあります。

X509Certificate cert = new X509Certificate(PathToCertificate,YourPassword); 
2

あなたはそれがパスワードでアクセスしていますしない限り、あなたのクライアント証明書ファイルが秘密鍵を含めることはできません

...少なくとも二つの問題...

初の可能性を持っています。クライアントが秘密鍵にアクセスできるように、PKCS#12(* .pfx)の証明書をパスワードとともに使用する必要があります。クライアントコードは、既に他の人が投稿しているので、証明書を開くときにパスワードを提供する必要があります。 ...

Process p = Process.Start(
    "makecert.exe", 
    String.Join(" ", new string[] { 
     "-r",//      Create a self signed certificate 
     "-pe",//     Mark generated private key as exportable 
     "-n", "CN=" + myHostName,// Certificate subject X500 name (eg: CN=Fred Dews) 
     "-b", "01/01/2000",//  Start of the validity period; default to now. 
     "-e", "01/01/2036",//  End of validity period; defaults to 2039 
     "-eku",//     Comma separated enhanced key usage OIDs 
     "1.3.6.1.5.5.7.3.1," +// Server Authentication (1.3.6.1.5.5.7.3.1) 
     "1.3.6.1.5.5.7.3.2", //  Client Authentication (1.3.6.1.5.5.7.3.2) 
     "-ss", "my",//    Subject's certificate store name that stores the output certificate 
     "-sr", "LocalMachine",// Subject's certificate store location. 
     "-sky", "exchange",//  Subject key type <signature|exchange|<integer>>. 
     "-sp",//     Subject's CryptoAPI provider's name 
     "Microsoft RSA SChannel Cryptographic Provider", 
     "-sy", "12",//    Subject's CryptoAPI provider's type 
     myHostName + ".cer"//  [outputCertificateFile] 
    }) 
); 

第二:これを作成するには、いくつかの方法がありますが、最も簡単で、その後、証明書に秘密キーをエクスポートするために、MMCの証明書マネージャを使用し、最初の証明書を生成するには、次のコマンドラインを使用することです

次の問題はサーバー側になります。サーバーはこの証明書を許可する必要があります。あなたは正しいロジックを持っていますが、ワイヤの間違った側で、この行をリクエストを処理するWebサーバーに移動します。あなたができない場合は、あなたは 'を取る必要があります。CER」ファイルサーバに保存された上で、サーバコンピュータの信頼リストに追加します。

ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true; 
+0

-1に証明書を登録しないと、私はそれを機能させることができません。サーバーは、クライアント証明書の秘密鍵を知る必要はありません。クライアント証明書に署名したCAだけを信頼する必要があります。 SSL3/TLSをネゴシエートする場合、サーバーは許可されているすべてのCAのDNを含むリストを送信します。その時点で、クライアントはクライアント証明書のCAを確認する必要があります。リストにあり、それを送信します。 – Gonzalo

+0

正解、私は決してSERVERが秘密鍵を必要としているとは言いませんでした。証明書を信頼するか、コードで明示的に許可する必要があります。あなたのコメントの残りの部分については、「...サーバはすべてのCAのDNを持つリストを送信します...」ということは、単に真実ではありません。 –

+1

本当ですか? http://tools.ietf.org/html/rfc5246#page-53のセクション7.4.4を参照してください:certificate_authorities 許容できる certificate_authoritiesの識別名[X501]のリスト。DERエンコード形式で表されます。これらの 識別名は、 ルートCAまたは従属CAに対して、必要な識別名を指定できます。したがって、このメッセージは、 が、既知のルートおよび所望の認可空間を記述するために使用することができる。 certificate_authoritiesリストが空の場合、クライアントは 適切なClientCertificateTypeの証明書を送信します。 unles – Gonzalo

2

潜在的な問題は、SSLセッション(のSchannelキャッシュ)のキャッシュである可能性があります。最初の要求だけがSSLハンドシェイクをネゴシエートします。後続のリクエストは、同じセッションIDを使用し、サーバーがそれを受け入れることを希望します。サーバーがSessionIdをクリアすると、要求は403エラーで失敗します。地元のSSLセッションのキャッシング(および各要求のための力のSSLネゴシエーション)を無効にするには、Windowsのレジストリフォルダ開くことがあります。

[HKEY_LOCAL_MACHINE] [システム] [CURRENTCONTROLSET] [コントロール] [SecurityProviders] [SCHANNEL]

をし、この問題は、ここで覆われている0

値でClientCacheTime(DWORD)という名前のキーを追加します。

http://support.microsoft.com/?id=247658

+0

これはかなり巨大です。あなたがこれを知らないなら、事実上意識的に物を壊している間に、あなたの "試行錯誤"の解決策を最も単純な形にしていると考えると、多くの時間を費やすことができます。 – Chazt3n

関連する問題