Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7970

WCF サービスが通信の暗号化に使っている証明書を WCF クライアント側で取り出す - present

$
0
0

WCFで NetTcpBinding を使った通信を SSL over TCPで暗号化しているときに、暗号化に使っているサーバー側の証明書をクライアント側で取得したくなった。主な目的は通信テスト。

SslStream で最初いけるかと思ったけど、即サーバー側から切断されてしまい、解決できず断念。別のアプローチを探したところ、WCFでの証明書の検証にカスタム証明書バリデーターを使うことで実現できた。

using System;
using System.IdentityModel.Selectors;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;

namespace SslCertSample
{
    internalclassProgram
    {
        staticvoid Main(string[] args)
        {
            var hostname = args[0];
            var port =int.Parse(args[1]);

            var binding =new NetTcpBinding();
            binding.Security.Mode = SecurityMode.Transport;
            binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
            binding.Security.Transport.SslProtocols = SslProtocols.Tls12;

            var address =new EndpointAddress(
                uri:new Uri($"net.tcp://{hostname}:{port}/GreetingService"),
                identity: EndpointIdentity.CreateDnsIdentity("your-domain.com"));

            var certificateValidator =new MyCertificateValidator();

            var factory =new ChannelFactory<IGreetingService>(
                binding: binding,
                remoteAddress: address);
            factory.Credentials.ServiceCertificate.SslCertificateAuthentication =new X509ServiceCertificateAuthentication
            {
                // 証明書の検証をカスタムにして、// サーバー証明書を取り出すためだけのカスタム証明書バリデーターを使う
                CertificateValidationMode = X509CertificateValidationMode.Custom,
                CustomCertificateValidator = certificateValidator,
            };

            var channel = factory.CreateChannel();

            var result = channel.Hello("Kubo");

            WriteCertificate(certificateValidator.Certificate);
            Console.WriteLine();

            foreach (var element in certificateValidator.Chain?.ChainElements)
            {
                WriteCertificate(element.Certificate);
                Console.WriteLine();
            }

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

        privatestaticvoid WriteCertificate(X509Certificate2 certificate)
        {
            Console.WriteLine($"Subject: {certificate?.Subject}");
            Console.WriteLine($"SubjectName: {certificate?.SubjectName.Name}");
            Console.WriteLine($"IssuerName: {certificate?.IssuerName.Name}");
        }
    }

    // サーバー証明書を取り出すためだけのカスタム証明書バリデーターpublicclassMyCertificateValidator : X509CertificateValidator, IDisposable
    {
        public X509Certificate2 Certificate { get; privateset; }

        public X509Chain Chain { get; privateset; }

        publicoverridevoid Validate(X509Certificate2 certificate)
        {
            Certificate = certificate;

            Chain =new X509Chain(useMachineContext:false)
            {
                ChainPolicy =new X509ChainPolicy
                {
                    // 証明書チェーンを取得するだけなので、チェックしない
                    RevocationMode = X509RevocationMode.NoCheck,
                },
            };
            Chain.Build(certificate);
        }

        publicvoid Dispose()
        {
            Chain?.Dispose();
        }
    }

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

Viewing all articles
Browse latest Browse all 7970

Trending Articles