証明書ストアにインストールされている証明書を WCF の TLS over TCP で使う

証明書ストアにインストールされているサーバー証明書を使って、WCFTLS over TCP を構成するサンプル。

using System;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;

namespace WcfCertStoreSample
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine($"使い方: WcfCertStoreSample.exe <thumbprint>");
                return;
            }

            var thumbprint = args[0];

            using (ServiceHost host = new ServiceHost(typeof(GreetingService)))
            {
                try
                {
                    // サーバー証明書を設定
                    host.Credentials.ServiceCertificate.SetCertificate(
                        storeLocation: StoreLocation.CurrentUser,
                        storeName: StoreName.My,
                        findType: X509FindType.FindByThumbprint,
                        findValue: thumbprint);

                    // セキュリティモードをTransportで設定
                    var binding = new NetTcpBinding();
                    binding.Security.Mode = SecurityMode.Transport;
                    binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
                    binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

                    // サービスホストにエンドポイントを追加
                    host.AddServiceEndpoint(
                        implementedContract: typeof(IGreetingService),
                        binding: binding,
                        address: new Uri($"net.tcp://localhost:8081/{nameof(IGreetingService)}"));

                    // サービスの開始
                    host.Open();

                    Console.WriteLine("サービス開始");
                    Console.WriteLine("Enterキーを押して終了");
                    Console.ReadLine();

                    // サービスの停止
                    host.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("エラー発生: " + ex.Message);
                    host.Abort();
                }
            }
        }
    }

    [ServiceContract]
    public interface IGreetingService
    {
        [OperationContract]
        string Hello(string name);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class GreetingService : IGreetingService
    {
        public string Hello(string name)
        {
            return $"Hello, {name}!";
        }
    }
}

クライアント側のサンプル。

using System;
using System.Net;
using System.ServiceModel;

namespace WcfCertStoreSample
{
    [ServiceContract]
    public interface IGreetingService
    {
        [OperationContract]
        string Hello(string name);
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine($"使い方: WcfCertStoreSample.Client.exe <dnsName>");
                return;
            }
            var dnsName = args[0];

            var binding = new NetTcpBinding();
            binding.Security.Mode = SecurityMode.Transport;
            binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
            binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

            var factory = new ChannelFactory<IGreetingService>(binding: binding);
            var channel = factory.CreateChannel(
                new EndpointAddress(
                    new Uri($"net.tcp://localhost:8081/{nameof(IGreetingService)}"),
                    EndpointIdentity.CreateDnsIdentity(dnsName)));
            var result = channel.Hello("Take");
            ((IClientChannel)channel).Close();
            factory.Close();

            Console.WriteLine(result);
            Console.WriteLine("Enter で終了");
            Console.ReadLine();
        }
    }
}