次の方法で共有


X.509 証明書検証ツール

このサンプルでは、カスタム X.509 証明書検証コントロールを実装する方法を示します。 これは、組み込みの X.509 証明書検証モードがアプリケーションの要件に適していない場合に便利です。 このサンプルでは、自己署名証明書を受け入れるカスタム検証コントロールを持つサービスを示します。 クライアントは、このような証明書を使用してサービスに対する認証を行います。

注: 誰でも自己発行証明書を作成できるため、サービスで使用されるカスタム 検証コントロールの安全性は、ChainTrust X509CertificateValidationMode によって提供される既定の動作よりも低くなります。 運用環境のコードでこの検証ロジックを使用する前に、このセキュリティへの影響を慎重に検討する必要があります。

要約すると、このサンプルは次の方法を示しています。

  • クライアントは、X.509 証明書を使用して認証できます。

  • サーバーは、カスタム X509CertificateValidator に対してクライアント資格情報を検証します。

  • サーバーは、サーバーの X.509 証明書を使用して認証されます。

サービスは、構成ファイル App.configを使用して定義された、サービスと通信するための単一のエンドポイントを公開します。エンドポイントは、アドレス、バインディング、およびコントラクトで構成されます。 バインディングは、既定で WSSecurity およびクライアント証明書認証を使用する標準wsHttpBindingで構成されます。 サービス動作では、クライアント X.509 証明書を検証するためのカスタム モードと、検証コントロール クラスの型を指定します。 この動作では、serviceCertificate 要素を使用してサーバー証明書も指定します。 サーバー証明書には、<serviceCertificate>のfindValueと同じ値をSubjectNameに含める必要があります。

  <system.serviceModel>
    <services>
      <service name="Microsoft.ServiceModel.Samples.CalculatorService"
               behaviorConfiguration="CalculatorServiceBehavior">
        <!-- use host/baseAddresses to configure base address -->
        <!-- provided by host -->
        <host>
          <baseAddresses>
            <add baseAddress =
                "http://localhost:8001/servicemodelsamples/service" />
          </baseAddresses>
        </host>
        <!-- use base address specified above, provide one endpoint -->
        <endpoint address="certificate"
               binding="wsHttpBinding"
               bindingConfiguration="Binding"
               contract="Microsoft.ServiceModel.Samples.ICalculator" />
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <!-- X509 certificate binding -->
        <binding name="Binding">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults ="true"/>
          <serviceCredentials>
            <!-- The serviceCredentials behavior allows one -->
            <!-- to specify authentication constraints on -->
            <!-- client certificates. -->
            <clientCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- Custom means that if the custom -->
              <!-- X509CertificateValidator does NOT throw -->
              <!-- an exception, then the provided certificate -->
              <!-- will be trusted without performing any -->
              <!-- validation beyond that performed by the custom -->
              <!-- validator. The security implications of this -->
              <!-- setting should be carefully considered before -->
              <!-- using Custom in production code. -->
              <authentication
                 certificateValidationMode="Custom"
                 customCertificateValidatorType =
"Microsoft.ServiceModel.Samples.CustomX509CertificateValidator, service" />
            </clientCertificate>
            <!-- The serviceCredentials behavior allows one to -->
            <!-- define a service certificate. -->
            <!-- A service certificate is used by a client to -->
            <!-- authenticate the service and provide message -->
            <!-- protection. This configuration references the -->
            <!-- "localhost" certificate installed during the setup -->
            <!-- instructions. -->
            <serviceCertificate findValue="localhost"
                 storeLocation="LocalMachine"
                 storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
      </system.serviceModel>

クライアント エンドポイント構成は、構成名、サービス エンドポイントの絶対アドレス、バインディング、コントラクトで構成されます。 クライアント バインドは、適切なモードとメッセージ clientCredentialTypeで構成されます。

<system.serviceModel>
    <client>
      <!-- X509 certificate based endpoint -->
      <endpoint name="Certificate"
        address=
        "http://localhost:8001/servicemodelsamples/service/certificate"
                binding="wsHttpBinding"
                bindingConfiguration="Binding"
                behaviorConfiguration="ClientCertificateBehavior"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>
    <bindings>
        <wsHttpBinding>
            <!-- X509 certificate binding -->
            <binding name="Binding">
                <security mode="Message">
                    <message clientCredentialType="Certificate" />
               </security>
            </binding>
       </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <serviceCertificate>
              <!-- Setting the certificateValidationMode to -->
              <!-- PeerOrChainTrust means that if the certificate -->
              <!-- is in the user's Trusted People store, then it -->
              <!-- is trusted without performing a validation of -->
              <!-- the certificate's issuer chain. -->
              <!-- This setting is used here for convenience so -->
              <!-- that the sample can be run without having to -->
              <!-- have certificates issued by a certification -->
              <!-- authority (CA). This setting is less secure -->
              <!-- than the default, ChainTrust. The security -->
              <!-- implications of this setting should be -->
              <!-- carefully considered before using -->
              <!-- PeerOrChainTrust in production code.-->
              <authentication
                  certificateValidationMode="PeerOrChainTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

クライアント実装は、使用するクライアント証明書を設定します。

// Create a client with Certificate endpoint configuration
CalculatorClient client = new CalculatorClient("Certificate");
try
{
    client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");

    // Call the Add service operation.
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

    // Call the Subtract service operation.
    value1 = 145.00D;
    value2 = 76.54D;
    result = client.Subtract(value1, value2);
    Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

    // Call the Multiply service operation.
    value1 = 9.00D;
    value2 = 81.25D;
    result = client.Multiply(value1, value2);
    Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

    // Call the Divide service operation.
    value1 = 22.00D;
    value2 = 7.00D;
    result = client.Divide(value1, value2);
    Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
    client.Close();
}
catch (TimeoutException e)
{
    Console.WriteLine("Call timed out : {0}", e.Message);
    client.Abort();
}
catch (CommunicationException e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}
catch (Exception e)
{
    Console.WriteLine("Call failed : {0}", e.Message);
    client.Abort();
}

このサンプルでは、カスタム X509CertificateValidator を使用して証明書を検証します。 このサンプルでは、 X509CertificateValidatorから派生した CustomX509CertificateValidator を実装しています。 詳細については、 X509CertificateValidator に関するドキュメントを参照してください。 この特定のカスタム 検証コントロール サンプルでは、次のコードに示すように、自己発行された X.509 証明書を受け入れるための Validate メソッドを実装しています。

public class CustomX509CertificateValidator : X509CertificateValidator
{
  public override void Validate ( X509Certificate2 certificate )
  {
   // Only accept self-issued certificates
   if (certificate.Subject != certificate.Issuer)
     throw new Exception("Certificate is not self-issued");
   }
}

サービス コードで検証コントロールを実装したら、使用する検証コントロール インスタンスについてサービス ホストに通知する必要があります。 これを行うには、次のコードを使用します。

serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new CustomX509CertificateValidator();

または、次のように構成で同じことを行うことができます。

<behaviors>
    <serviceBehaviors>
     <behavior name="CalculatorServiceBehavior">
       ...
   <serviceCredentials>
    <!--The serviceCredentials behavior allows one to specify -->
    <!--authentication constraints on client certificates.-->
    <clientCertificate>
    <!-- Setting the certificateValidationMode to Custom means -->
    <!--that if the custom X509CertificateValidator does NOT -->
    <!--throw an exception, then the provided certificate will -->
    <!--be trusted without performing any validation beyond that -->
    <!--performed by the custom validator. The security -->
    <!--implications of this setting should be carefully -->
    <!--considered before using Custom in production code. -->
    <authentication certificateValidationMode="Custom"
       customCertificateValidatorType =
"Microsoft.ServiceModel.Samples. CustomX509CertificateValidator, service" />
   </clientCertificate>
   </serviceCredentials>
   ...
  </behavior>
 </serviceBehaviors>
</behaviors>

サンプルを実行すると、操作要求と応答がクライアント コンソール ウィンドウに表示されます。 クライアントは、すべてのメソッドを正常に呼び出す必要があります。 クライアント ウィンドウで Enter キーを押して、クライアントをシャットダウンします。

Batch ファイルのセットアップ

このサンプルに用意されている Setup.bat バッチ ファイルを使用すると、適切な証明書を使用してサーバーを構成し、サーバー証明書ベースのセキュリティを必要とする自己ホスト型アプリケーションを実行できるようになります。 このバッチ ファイルは、コンピューター間で動作するように、またはホストされていないケースで動作するように変更する必要があります。

次に、適切な構成で実行するように変更できるように、バッチ ファイルのさまざまなセクションの概要を示します。

  • サーバー証明書の作成:

    Setup.bat バッチ ファイルの次の行は、使用するサーバー証明書を作成します。 %SERVER_NAME% 変数は、サーバー名を指定します。 この変数を変更して、独自のサーバー名を指定します。 既定値は localhost です。

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • クライアントの信頼された証明書ストアへのサーバー証明書のインストール:

    Setup.bat バッチ ファイル内の次の行は、クライアントの信頼できるユーザー ストアにサーバー証明書をコピーします。 Makecert.exe によって生成された証明書はクライアント システムによって暗黙的に信頼されないため、この手順が必要です。 クライアントの信頼されたルート証明書 (Microsoft が発行した証明書など) にルート化された証明書が既にある場合、クライアント証明書ストアにサーバー証明書を設定するこの手順は必要ありません。

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • クライアント証明書の作成:

    Setup.bat バッチ ファイルの次の行は、使用するクライアント証明書を作成します。 %USER_NAME% 変数は、クライアント名を指定します。 これはクライアント コードが検索する名前であるため、この値は "test1" に設定されます。 %USER_NAME% の値を変更する場合は、Client.cs ソース ファイル内の対応する値を変更し、クライアントをリビルドする必要があります。

    証明書は、CurrentUser ストアの場所の下の個人用 (個人用) ストアに格納されます。

    echo ************
    echo Client cert setup starting
    echo %USER_NAME%
    echo ************
    echo making client cert
    echo ************
    makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%USER_NAME% -sky exchange -pe
    
  • クライアント証明書をサーバーの信頼された証明書ストアにインストールする:

    Setup.bat バッチ ファイル内の次の行は、クライアント証明書を信頼されたユーザー ストアにコピーします。 Makecert.exe によって生成された証明書はサーバー システムによって暗黙的に信頼されないため、この手順が必要です。 信頼されたルート証明書 (Microsoft が発行した証明書など) にルート化された証明書が既にある場合、サーバー証明書ストアにクライアント証明書を設定するこの手順は必要ありません。

    certmgr.exe -add -r CurrentUser -s My -c -n %USER_NAME% -r LocalMachine -s TrustedPeople
    

サンプルを設定してビルドするには

  1. ソリューションをビルドするには、「 Windows Communication Foundation サンプルのビルド」の手順に従います。

  2. サンプルを単一コンピューター構成で実行するか、複数コンピューター構成で実行するかに応じて、次の手順に従います。

同じコンピューターでサンプルを実行するには

  1. 管理者特権で開いた Visual Studio コマンド プロンプト内のサンプル インストール フォルダーから Setup.bat を実行します。 これにより、サンプルの実行に必要なすべての証明書がインストールされます。

    Von Bedeutung

    Setup.bat バッチ ファイルは、Visual Studio コマンド プロンプトから実行するように設計されています。 Visual Studio コマンド プロンプト内で設定された PATH 環境変数は、Setup.bat スクリプトに必要な実行可能ファイルを含むディレクトリを指します。

  2. service\bin から Service.exe を起動します。

  3. \client\bin から Client.exe を起動します。 クライアント アクティビティがクライアント コンソール アプリケーションに表示されます。

  4. クライアントとサービスが通信できない場合は、「WCF サンプルのトラブルシューティングのヒント」を参照してください。

複数のコンピューターでサンプルを実行するには

  1. サービス コンピューター上にディレクトリを作成します。

  2. サービス プログラム ファイルを \service\bin からサービス コンピューター上の仮想ディレクトリにコピーします。 また、Setup.bat、Cleanup.bat、GetComputerName.vbs、ImportClientCert.bat ファイルをサービス コンピューターにコピーします。

  3. クライアント コンピューター上にクライアント バイナリ用のディレクトリを作成します。

  4. クライアント プログラム ファイルをクライアント コンピューター上のクライアント ディレクトリにコピーします。 また、Setup.bat、Cleanup.bat、および ImportServiceCert.bat ファイルをクライアントにコピーします。

  5. サーバーで、管理者特権で開かれた Visual Studio の開発者コマンド プロンプトで setup.bat service を実行します。 setup.bat 引数を指定して service を実行すると、コンピューターの完全修飾ドメイン名を持つサービス証明書が作成され、サービス証明書が Service.cer という名前のファイルにエクスポートされます。

  6. Service.exe.config を編集して、コンピューターの完全修飾ドメイン名と同じ新しい証明書名 (<serviceCertificate のfindValue属性>) を反映します。 また、 <service>/<baseAddresses> 要素のコンピューター名を localhost からサービス コンピューターの完全修飾名に変更します。

  7. Service.cer ファイルをサービス ディレクトリからクライアント コンピューター上のクライアント ディレクトリにコピーします。

  8. クライアントで、管理者特権で開かれた Visual Studio の開発者コマンド プロンプトで setup.bat client を実行します。 setup.bat 引数で client を実行すると、client.com という名前のクライアント証明書が作成され、クライアント証明書が Client.cer という名前のファイルにエクスポートされます。

  9. クライアント コンピューター上の Client.exe.config ファイルで、サービスの新しいアドレスと一致するようにエンドポイントのアドレス値を変更します。 これを行うには、localhost をサーバーの完全修飾ドメイン名に置き換えます。

  10. Client.cer ファイルをクライアント ディレクトリからサーバー上のサービス ディレクトリにコピーします。

  11. クライアントで、管理者特権で開かれた Visual Studio の開発者コマンド プロンプトで ImportServiceCert.bat を実行します。 これにより、Service.cer ファイルから CurrentUser - TrustedPeople ストアにサービス証明書がインポートされます。

  12. サーバーで、管理者特権で開かれた Visual Studio の開発者コマンド プロンプトで ImportClientCert.bat を実行します。 これにより、Client.cer ファイルから LocalMachine - TrustedPeople ストアにクライアント証明書がインポートされます。

  13. サーバー コンピューターで、コマンド プロンプト ウィンドウから Service.exe を起動します。

  14. クライアント コンピューターで、コマンド プロンプト ウィンドウから Client.exe を起動します。 クライアントとサービスが通信できない場合は、「WCF サンプルのトラブルシューティングのヒント」を参照してください。

サンプルの実行後にクリーンアップするには

  1. サンプルの実行が完了したら、samples フォルダーで Cleanup.bat を実行します。 これにより、証明書ストアからサーバー証明書とクライアント証明書が削除されます。

このスクリプトは、コンピューター間でこのサンプルを実行するときに、クライアント上のサービス証明書を削除しません。 コンピューター間で証明書を使用する Windows Communication Foundation (WCF) サンプルを実行している場合は、CurrentUser - TrustedPeople ストアにインストールされているサービス証明書を必ずクリアしてください。 これを行うには、次のコマンドを使用します。 certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name> 例: certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com.