証明書ファイルを読み込んで WCF の SSL over TCP で使う

WCF は NetTcpBinding を使う場合でも SSL で通信を暗号化できる。

暗号化に使う SSL 証明書は、Windows の証明書ストアにインストールしてある中から検索して使うのが一般的なやり方っぽいが、 インストールしていない証明書のファイルを読み込んで使うことも可能。

コードはこんな感じ。WCF サービスをセルフホストするのに、Topshelf を使っている。

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

namespace WcfSample.Service
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(config =>
            {
                config.Service<ServiceHost>(service =>
                {
                    service.ConstructUsing(settings =>
                    {
                        var certPath = Path.Combine(
                            AppDomain.CurrentDomain.BaseDirectory,
                            "cert",
                            "certfile.pfx");

                        // 証明書ストアに証明書が一時的に格納されるので、
                        // 格納場所を指定しておかないとデフォルトの場所に格納されてしまう。
                        // その場合管理者権限が必要になってしまうので、
                        // 現在のユーザーのストアに格納するように指定した。
                        var cert = new X509Certificate2(certPath, "password", X509KeyStorageFlags.UserKeySet);

                        var host = new ServiceHost(typeof(SampleService));
                        host.Credentials.ServiceCertificate.Certificate = cert;
                        return host;
                    });
                    
                    service.WhenStarted(host => host.Open());

                    service.WhenStopped(host =>
                    {
                        host.Close();
                    });
                });

                config.RunAsNetworkService();
                config.SetDescription("WCF サンプルサービス");
                config.SetDisplayName("WCF サンプルサービス");
                config.SetServiceName("WcfSampleService");
            });
        }
    }
}

アプリケーション構成ファイルも載せておく。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="SampleServiceTcp">
                    <security mode="Transport">
                        <transport clientCredentialType="None" protectionLevel="EncryptAndSign" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <services>
            <service name="WcfSample.Service.SampleService">
                <endpoint address="net.tcp://localhost:808/SampleService" binding="netTcpBinding"
                    bindingConfiguration="SampleServiceTcp" contract="WcfSample.Common.ISampleService" />
            </service>
        </services>
    </system.serviceModel>
</configuration>