方法 : カスタム証明書検証を使用するサービスを作成する

このトピックでは、カスタム証明書検証を実装する方法、クライアントまたはサービスの資格情報の設定により、既定の証明書検証機能を、カスタム証明書検証で置き換える方法について解説します。

X.509 証明書を使ってクライアントやサービスを認証する場合、Windows Communication Foundation (WCF) の既定では、Windows 証明書ストアと Crypto API を使用して証明書が検証され、信頼できるかどうかが確認されます。ところが、組み込みの検証機能では不充分で、処理内容を変更しなければならない場合もあります。WCF では、ユーザーがカスタムの証明書検証機能を追加して、検証ロジックを簡単に変更できます。カスタムの証明書検証機能が指定されている場合、WCF では、組み込みの検証機能ではなく、カスタムの検証処理のみが使用されます。

手順

カスタムの証明書検証機能を作成するには

  1. X509CertificateValidator から派生する新しいクラスを定義します。

  2. 抽象メソッドである Validate を実装します。検証対象の証明書が、引数としてこのメソッドに渡されます。検証処理の結果、証明書が有効ではないと判断されると、このメソッドは、SecurityTokenValidationException という例外をスローします。有効であればそのまま呼び出し元に制御を返します。

    ms733806.note(ja-jp,VS.100).gif注 :
    クライアントに認証エラーを返すには、Validate メソッドで FaultException をスローします。

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
public class MyX509CertificateValidator : X509CertificateValidator
{
    string allowedIssuerName;

    public MyX509CertificateValidator(string allowedIssuerName)
    {
        if (allowedIssuerName == null)
        {
            throw new ArgumentNullException("allowedIssuerName");
        }

        this.allowedIssuerName = allowedIssuerName;
    }

    public override void Validate(X509Certificate2 certificate)
    {
        // Check that there is a certificate.
        if (certificate == null)
        {
            throw new ArgumentNullException("certificate");
        }

        // Check that the certificate issuer matches the configured issuer.
        if (allowedIssuerName != certificate.IssuerName.Name)
        {
            throw new SecurityTokenValidationException
              ("Certificate was not issued by a trusted issuer");
        }
    }
}

サービス構成でカスタム検証処理を指定するには

  1. <system.ServiceModel> 要素に <behaviors> 要素と serviceBehaviors section を追加します。

  2. Behavior elementを追加し、name 属性に適切な値を設定します。

  3. <behavior> 要素に <serviceCredentials> Elementを追加します。

  4. <serviceCredentials> 要素に <clientCertificate> 要素を追加します。

  5. <clientCertificate> 要素に <authentication> of <clientCertificate> Element を追加します。

  6. customCertificateValidatorType 属性に検証処理の型を設定します。この属性に型の名前空間と名前を設定する例を以下に示します。

  7. certificateValidationMode 属性を Custom に設定します。

    <configuration>
     <system.serviceModel>
      <behaviors>
       <serviceBehaviors>
        <behavior name="ServiceBehavior">
         <serviceCredentials>
          <clientCertificate>
          <authentication certificateValidationMode="Custom" customCertificateValidatorType="Samples.MyValidator, service" />
          </clientCertificate>
         </serviceCredentials>
        </behavior>
       </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
    </configuration>
    

クライアント側の設定でカスタム証明書検証を指定するには

  1. <system.ServiceModel> 要素に <behaviors> 要素と serviceBehaviors section を追加します。

  2. <endpointBehaviors> 要素を追加します。

  3. <behavior> 要素を追加し、name 属性に適切な値を設定します。

  4. <clientCredentials> 要素を追加します。

  5. <serviceCertificate> of <clientCredentials> Element を追加します。

  6. 次の例に示すように、<authentication> of <serviceCertificate> Element を追加します。

  7. customCertificateValidatorType 属性に検証処理の型を設定します。

  8. certificateValidationMode 属性を Custom に設定します。この属性に型の名前空間と名前を設定する例を以下に示します。

    <configuration>
     <system.serviceModel>
      <behaviors>
       <endpointBehaviors>
        <behavior name="clientBehavior">
         <clientCredentials>
          <serviceCertificate>
           <authentication certificateValidationMode="Custom" 
                  customCertificateValidatorType=
             "Samples.CustomX509CertificateValidator, client"/>
          </serviceCertificate>
         </clientCredentials>
        </behavior>
       </endpointBehaviors>
      </behaviors>
     </system.serviceModel>
    </configuration>
    

サービス側のコードでカスタム証明書検証を指定するには

  1. ClientCertificate プロパティの値としてカスタム証明書検証を指定します。サービスの資格情報には、Credentials プロパティを使用してアクセスできます。

  2. CertificateValidationMode プロパティを Custom に設定します。

serviceHost.Credentials.ClientCertificate.Authentication. _
    CertificateValidationMode = X509CertificateValidationMode.Custom
serviceHost.Credentials.ClientCertificate.Authentication. _
   CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
    X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
    new MyX509CertificateValidator("CN=Contoso.com");

クライアント側のコードでカスタム証明書検証を指定するには

  1. カスタム証明書検証を、CustomCertificateValidator プロパティを使って指定します。クライアントの資格情報には、Credentials プロパティを使用してアクセスできます。ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) によって生成されるクライアント クラスは、常に ClientBase クラスから派生したものです。

  2. CertificateValidationMode プロパティを Custom に設定します。

説明

カスタム証明書検証を実装し、サービス側で使用する例を以下に示します。

コード

Imports System
Imports System.IdentityModel.Selectors
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions

<assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution := True)>
<ServiceContract([Namespace] := "http://Microsoft.ServiceModel.Samples")>  _
Public Interface ICalculator
    <OperationContract()>  _
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 
End Interface 


Public Class CalculatorService
    Implements ICalculator
    
    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double _
       Implements ICalculator.Add
        Dim result As Double = n1 + n2
        Return result    
    End Function 
End Class 


Class Program
    
    Shared Sub Main() 
        Dim serviceHost As New ServiceHost(GetType(CalculatorService))
        Try
            serviceHost.Credentials.ClientCertificate.Authentication. _
                CertificateValidationMode = X509CertificateValidationMode.Custom
            serviceHost.Credentials.ClientCertificate.Authentication. _
               CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
            serviceHost.Open()
            Console.WriteLine("Service started, press ENTER to stop ...")
            Console.ReadLine()
            
            serviceHost.Close()
        Finally
            serviceHost.Close()
        End Try
    
    End Sub 
End Class 

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;

using System.Security.Permissions;

[assembly: SecurityPermission(
   SecurityAction.RequestMinimum, Execution = true)]
namespace Microsoft.ServiceModel.Samples
{ 
    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
    }

    public class CalculatorService : ICalculator
    {
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }
    }

    class Program
    {
        static void Main()
        {
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
            {
                serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
                    X509CertificateValidationMode.Custom;
                serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
                    new MyX509CertificateValidator("CN=Contoso.com");

                serviceHost.Open();
                Console.WriteLine("Service started, press ENTER to stop ...");
                Console.ReadLine();

                serviceHost.Close();
            }
        }
    }

    public class MyX509CertificateValidator : X509CertificateValidator
    {
        string allowedIssuerName;

        public MyX509CertificateValidator(string allowedIssuerName)
        {
            if (allowedIssuerName == null)
            {
                throw new ArgumentNullException("allowedIssuerName");
            }

            this.allowedIssuerName = allowedIssuerName;
        }

        public override void Validate(X509Certificate2 certificate)
        {
            // Check that there is a certificate.
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            // Check that the certificate issuer matches the configured issuer.
            if (allowedIssuerName != certificate.IssuerName.Name)
            {
                throw new SecurityTokenValidationException
                  ("Certificate was not issued by a trusted issuer");
            }
        }
    }
}

参照

リファレンス

X509CertificateValidator