context: using XKMS2WSNamespace;
  using System;
  using System.Net;
  using System.Net.Security;
  using System.Security.Cryptography.X509Certificates;
  using System.ServiceModel;
  using System.ServiceModel.Channels;
  using System.ServiceModel.Description;
  using System.ServiceModel.Dispatcher;
  using System.ServiceModel.Security;
  using System.ServiceModel.Security.Tokens;
  using System.Collections.Generic;
  using Org.BouncyCastle.Ocsp;
  using Org.BouncyCastle.X509;
  using Org.BouncyCastle.Tsp;
  using Org.BouncyCastle.Crypto;
  using Org.BouncyCastle.Security;
  using Org.BouncyCastle.Crypto.Parameters;
  using System.Security.Cryptography;
  
  namespace eid_trust_service_sdk_dotnet
  {
      /// <summary>
      /// Client implementation of the eID Trust Service XKMS2 Web Service.
      /// </summary>
      public class XkmsClientImpl : XkmsClient
      {
          private X509Certificate2 sslCertificate;
          private X509Certificate2 serverCertificate;
          private X509Certificate2 clientCertificate;
  
          private String location;
  
          private XKMSPortTypeClient client;
  
          private RevocationValuesType revocationValues;
          private LinkedList<String> invalidReasonURIs = new LinkedList<String>();
  
          private bool CertificateValidationCallback(Object sender,
              System.Security.Cryptography.X509Certificates.X509Certificate certificate,
              X509Chain chain,
              SslPolicyErrors sslPolicyErrors)
          {
              Console.WriteLine("Certificate Validation Callback");
              bool result = certificate.Equals(this.sslCertificate);
              Console.WriteLine("TSL Authn result: " + result);
              return result;
          }
  
          /// <summary>
          /// Default constructor.
          /// 
          /// Set the optional authentication modes (unilateral TLS and/or WS-Security) afterwards.
          /// </summary>
          /// <param name="location">Full path of the eID Trust Service</param>
          public XkmsClientImpl(string location)
          {
              this.location = location;
          }
  
          public void configureSsl(X509Certificate2 sslCertificate)
          {
              this.sslCertificate = sslCertificate;
          }
  
          public void configureWSSecurity(X509Certificate2 serverCertificate, X509Certificate2 clientCertificate)
          {
              this.serverCertificate = serverCertificate;
              this.clientCertificate = clientCertificate;
              if (null == this.clientCertificate)
              {
                  // here we generate a temporary self-signed certificate and key pair for signing the request.
                  AsymmetricCipherKeyPair keyPair = KeyStoreUtil.GenerateKeyPair();
                  this.clientCertificate = new X509Certificate2(
                      DotNetUtilities.ToX509Certificate(
                      KeyStoreUtil.CreateCert("CN=Temp", keyPair.Public, keyPair.Private)));
                  this.clientCertificate.PrivateKey = KeyStoreUtil.getRSAPrivateKey(keyPair.Private, true);
              }
          }
  
          private void setupClient()
          {
              EndpointAddress remoteAddress = new EndpointAddress(this.location);
  
              bool sslLocation = this.location.StartsWith("https") ? true : false;
              if (sslLocation)
              {
                  if (null != this.sslCertificate)
                  {
                      /*
                       * Setup SSL validation
                       */
                      Console.WriteLine("SSL validation active");
                      ServicePointManager.ServerCertificateValidationCallback =
                          new RemoteCertificateValidationCallback(CertificateValidationCallback);
                  }
                  else
                  {
                      ServicePointManager.ServerCertificateValidationCallback =
                          new RemoteCertificateValidationCallback(WCFUtil.AnyCertificateValidationCallback);
                  }
              }
  
              if (null != this.serverCertificate)
              {
                  /*
                   * Setup WS-Security
                   */
                  Console.WriteLine("WS-Security active");
                  this.client = new XKMSPortTypeClient(new WSSecurityBinding(sslLocation, this.serverCertificate), remoteAddress);
                  // set credentials
                  this.client.ClientCredentials.ServiceCertificate.DefaultCertificate = this.serverCertificate;
                  this.client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
                      X509CertificateValidationMode.None;
                  this.client.ClientCredentials.ClientCertificate.Certificate = this.clientCertificate;
                  // set contract
                  this.client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
              }
  
              if (null == this.client)
              {
                  // Setup basic client without WS-Security binding
                  if (sslLocation)
                  {
                      this.client = new XKMSPortTypeClient(WCFUtil.BasicHttpOverSSLBinding(), remoteAddress);
                  }
                  else
                  {
                      this.client = new XKMSPortTypeClient(new BasicHttpBinding(), remoteAddress);
                  }
              }
  
              // add logging behaviour
              this.client.Endpoint.Behaviors.Add(new LoggingBehavior());
          }
  
          public void validate(List<Org.BouncyCastle.X509.X509Certificate> certificateChain)
          {
              validate(certificateChain, null, false, DateTime.MinValue, null, null, null, null, null);
          }
  
          public void validate(List<Org.BouncyCastle.X509.X509Certificate> certificateChain,
              bool returnRevocationData)
          {
              validate(certificateChain, null, returnRevocationData, DateTime.MinValue, null, null, null, null, null);
          }
  
          public void validate(string trustDomain, List<Org.BouncyCastle.X509.X509Certificate> certificateChain)
          {
              validate(certificateChain, trustDomain, false, DateTime.MinValue, null, null, null, null, null);
          }
  
          public void validate(string trustDomain, List<Org.BouncyCastle.X509.X509Certificate> certificateChain,
              bool returnRevocationData)
          {
              validate(certificateChain, trustDomain, returnRevocationData, DateTime.MinValue, null, null, null, null, null);
          }
  
          public void validate(string trustDomain, List<Org.BouncyCastle.X509.X509Certificate> certificateChain,
              DateTime validationDate, List<OcspResp> ocspResponses, List<X509Crl> crls)
          {
              validate(certificateChain, trustDomain, false, validationDate, ocspResponses, crls, null, null, null);
          }
  
          public void validate(string trustDomain, List<Org.BouncyCastle.X509.X509Certificate> certificateChain,
              DateTime validationDate, RevocationValuesType revocationValues)
          {
              validate(certificateChain, trustDomain, false, validationDate, null, null, revocationValues, null, null);
          }
  
          public void validate(string trustDomain, TimeStampToken timeStampToken)
          {
              validate(null, trustDomain, false, DateTime.MinValue, null, null, null, timeStampToken, null);
          }
  
          public void validate(string trustDomain, List<Org.BouncyCastle.X509.X509Certificate> certificateChain,
              EncapsulatedPKIDataType[] attributeCertificates)
          {
              validate(certificateChain, trustDomain, false, DateTime.MinValue, null, null, null, null, attributeCertificates);
          }
  
          public LinkedList<string> getInvalidReasons()
          {
              return this.invalidReasonURIs;
          }
  
          public RevocationValuesType getRevocationValues()
          {
              return this.revocationValues;
          }
  
          /*
           * Validation
           */
          private void validate(List<Org.BouncyCastle.X509.X509Certificate> certificateChain, string trustDomain,
              bool returnRevocationData, DateTime validationDate, List<OcspResp> ocspResponses, List<X509Crl> crls,
              RevocationValuesType revocationValues, TimeStampToken timeStampToken,
              EncapsulatedPKIDataType[] attributeCertificates)
          {
              // setup the client
              setupClient();
  
              // validate
              ValidateRequestType validateRequest = new ValidateRequestType();
              QueryKeyBindingType queryKeyBinding = new QueryKeyBindingType();
              KeyInfoType keyInfo = new KeyInfoType();
              X509DataType x509Data = new X509DataType();
              x509Data.Items = new object[certificateChain.Count];
              x509Data.ItemsElementName = new ItemsChoiceType[certificateChain.Count];
              int idx = 0;
              foreach (Org.BouncyCastle.X509.X509Certificate certificate in certificateChain)
              {
                  x509Data.Items[idx] = certificate.GetEncoded();
                  x509Data.ItemsElementName[idx] = ItemsChoiceType.X509Certificate;
                  idx++;
              }
              keyInfo.Items = new object[] { x509Data };
              keyInfo.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.X509Data };
              queryKeyBinding.KeyInfo = keyInfo;
              validateRequest.QueryKeyBinding = queryKeyBinding;
  
              /*
               * Set optional trust domain 
               */
  
gt:             if (null != trustDomain)