none
how to configure WCF with SSL and an x.509 client certificate RRS feed

  • Question

  • I have a WCF service that I'm hosting in IIS. I have an SSL certificate installed on the server and I would like to use wsHttpBiniding that uses that certificate. Also, I like my client application to use a x.509 certificate to communicate with my service. How do I need to change my config files on the service and client side to accomplish this?

    Here's what I have right now in my web.config and app.config. I know that my config's are incorrect, please feel free to suggest modifications. Thanks.

    Web.config:

    <system.serviceModel>   
        <bindings>
          <wsHttpBinding>
            <binding name="WsBinding_IGatewayService"
                     maxReceivedMessageSize="2147483647"
                     openTimeout="00:25:00"
                     closeTimeout="00:25:00"
                     sendTimeout="00:25:00"
                     receiveTimeout="00:25:00">
              <readerQuotas maxArrayLength="2147483647"
                            maxBytesPerRead="2147483647"
                            maxDepth="2147483647"
                            maxNameTableCharCount="2147483647"
                            maxStringContentLength="2147483647"/>
              <security mode="Transport">
                <transport clientCredentialType="Certificate"/>
              </security>
            </binding>       
          </wsHttpBinding>
          <basicHttpBinding>
            <binding name="BasicBinding_IGatewayService"
                     maxReceivedMessageSize="2147483647"
                     openTimeout="00:25:00"
                     closeTimeout="00:25:00"
                     sendTimeout="00:25:00"
                     receiveTimeout="00:25:00">
              <readerQuotas maxArrayLength="2147483647"
                            maxBytesPerRead="2147483647"
                            maxDepth="2147483647"
                            maxNameTableCharCount="2147483647"
                            maxStringContentLength="2147483647"/>
            </binding>
          </basicHttpBinding>
        </bindings>
        <services>
          <service name="nacr.Services.Integration.TelAgentDataGateway.GatewayService">
            <endpoint address=""
                      binding="wsHttpBinding"
                      bindingConfiguration="WsBinding_IGatewayService"
                      name="GatewayServiceEndpoint"
                      contract="nacr.Services.Integration.TelAgentDataGateway.IGatewayService" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          </service>
        </services>   
        <behaviors>
          <serviceBehaviors>
            <behavior>         
              <serviceMetadata httpGetEnabled="true"/>        
              <serviceDebug includeExceptionDetailInFaults="true"/>
              <dataContractSerializer maxItemsInObjectGraph="2147483647" />         
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
      </system.serviceModel>

    Client app.config:

    <system.serviceModel>
            <bindings>
                <wsHttpBinding>
                    <binding name="GatewayServiceEndpoint" closeTimeout="00:01:00"
                        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                        bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                        maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                        messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                        allowCookies="false">
                        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <reliableSession ordered="true" inactivityTimeout="00:10:00"
                            enabled="false" />
                      <security mode="Transport">
                            <transport clientCredentialType="Windows" proxyCredentialType="None"
                                realm="" />
                            <message clientCredentialType="Windows" negotiateServiceCredential="true"
                                algorithmSuite="Default" />
                        </security>
                    </binding>
                </wsHttpBinding>
            </bindings>
            <client>
                <endpoint address="http://localhost:59629/GatewayService.svc"
                    binding="wsHttpBinding" bindingConfiguration="GatewayServiceEndpoint"
                    contract="GatewayServiceReference.IGatewayService" name="GatewayServiceEndpoint">
                    <identity>
                        <userPrincipalName value="DontKnow" />
                    </identity>
                </endpoint>
            </client>
    </system.serviceModel>


    Wednesday, March 7, 2012 10:08 PM

Answers

  • That should be fine just make sure that when making the call you fetch your client certificate and add it to the request.

    SampleServiceClient objClient = new SampleServiceClient();                       
                objClient.ClientCredentials.ClientCertificate.Certificate = (X509Certificate2)GetX509Certificate();
    
    
    private static X509Certificate GetX509Certificate()
            {
                X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                store.Open(OpenFlags.OpenExistingOnly);
                X509Certificate certificate = null;
                
                X509Certificate2Collection cers = store.Certificates.Find(X509FindType.FindBySubjectName, "client.com", false);
                if (cers.Count > 0)
                {
                    certificate = cers[0];
                }
                store.Close();
                return certificate;
            }


    Rajesh S V

    • Marked as answer by Yi-Lun Luo Wednesday, March 14, 2012 9:34 AM
    Friday, March 9, 2012 9:37 AM

All replies

  • In order to get a 2 way SSL you need to have few more config entries on the server as shown below:

    <serviceBehaviors>
            <behavior>          
              <serviceMetadata httpGetEnabled="true"/>         
              <serviceDebug includeExceptionDetailInFaults="true"/>
              <dataContractSerializer maxItemsInObjectGraph="2147483647" />          
               <serviceCredentials>
                       <clientCertificate>
                             <authentication certificateValidationMode="PeerOrChainTrust" />
                       </clientCertificate>
                       <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>


    NOTE: You need to specify the same certificate that you have used to install on the IIS. Now once you have them

    You need to install the certificates in your certificate store as described below:

    You need to have the client certificate as follows:

    On the client machine :

             Current User --> Personal folder should have client certificate MyClientCert.pfx installed

    On Server machines:

             Local Machine --> TrusterPeople should have MyClientCert.cer installed

    You need to have the server certificate as follows:

    On the server machine:

          Local Machine --> Personal folder

    On the client machine:

         Either the certificate issuer or server certificate needs to be present in 

          Local Machine --> Trusted People store

    If you are using self signed certificates then you also need to use the below code on your client to bypass the server certificate validity:

    System.Net.ServicePointManager.ServerCertificateValidationCallback =  (sender, certificate, chain, errors) => true;

    • Edited by Rajesh S V Thursday, March 8, 2012 9:33 AM
    Thursday, March 8, 2012 9:21 AM
  • got it. One quick question:

    Do I need to make any changes to my clinet's app.config or does that look ok?

    thank you.

    Thursday, March 8, 2012 3:09 PM
  • That should be fine just make sure that when making the call you fetch your client certificate and add it to the request.

    SampleServiceClient objClient = new SampleServiceClient();                       
                objClient.ClientCredentials.ClientCertificate.Certificate = (X509Certificate2)GetX509Certificate();
    
    
    private static X509Certificate GetX509Certificate()
            {
                X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                store.Open(OpenFlags.OpenExistingOnly);
                X509Certificate certificate = null;
                
                X509Certificate2Collection cers = store.Certificates.Find(X509FindType.FindBySubjectName, "client.com", false);
                if (cers.Count > 0)
                {
                    certificate = cers[0];
                }
                store.Close();
                return certificate;
            }


    Rajesh S V

    • Marked as answer by Yi-Lun Luo Wednesday, March 14, 2012 9:34 AM
    Friday, March 9, 2012 9:37 AM