Message Security with Mutual Certificates

 

The following scenario shows a Windows Communication Foundation (WCF) service and client secured using message security mode. The client and the service are authenticated with certificates.

This scenario is interoperable because it uses WS-Security with the X.509 certificate token profile.

System_CAPS_ICON_note.jpg Note

This scenario does not perform negotiation of the service certificate. The service certificate must be provided to the client in advance of any communication. The server certificate can be distributed with the application or provided in an out-of-band communication.

Message security with mutual certificates

CharacteristicDescription
Security ModeMessage
InteroperabilityYes, with WS-Security and X.509 certificate token profile compatible clients and services.
AuthenticationMutual authentication of the server and client.
IntegrityYes
ConfidentialityYes
TransportHTTP
BindingWSHttpBinding

The following code and configuration are meant to run independently. Do one of the following:

  • Create a stand-alone service using the code with no configuration.

  • Create a service using the supplied configuration, but do not define any endpoints.

Code

The following code shows creates a service endpoint that uses message security. The service requires a certificate to authenticate itself.

            // Create the binding. 
            WSHttpBinding binding = new WSHttpBinding();
            binding.Security.Mode = SecurityMode.Message;
            binding.Security.Message.ClientCredentialType =
                MessageCredentialType.Certificate;
            binding.Security.Message.NegotiateServiceCredential = false;
            binding.Security.Message.EstablishSecurityContext = false;

            // Create the URI for the endpoint.
            Uri httpUri = new Uri("http://localhost/Calculator");

            // Create the service host.
            ServiceHost myServiceHost =
                new ServiceHost(typeof(Calculator), httpUri);

            // Specify a certificate to authenticate the service.
            myServiceHost.Credentials.ServiceCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindBySubjectName,
                "contoso.com");

            // Add an endpoint to the service.
            myServiceHost.AddServiceEndpoint(typeof(ICalculator), binding, "");

            // Open the service.
            myServiceHost.Open();
            Console.WriteLine("Listening...");
            Console.ReadLine();

            // Close the service.
            myServiceHost.Close();

Configuration

The following configuration can be used instead of the code to create the same service.

<?xml version="1.0" encoding="utf-8"?>  
<configuration>  
  <system.serviceModel>  
    <behaviors>  
      <serviceBehaviors>  
        <behavior name="serviceCredentialBehavior">  
          <serviceCredentials>  
            <serviceCertificate findValue="Contoso.com"   
                                storeLocation="LocalMachine"  
                                storeName="My"   
                                x509FindType="FindBySubjectName" />  
          </serviceCredentials>  
        </behavior>  
      </serviceBehaviors>  
    </behaviors>  
    <services>  
      <service behaviorConfiguration="serviceCredentialBehavior"   
               name="ServiceModel.Calculator">  
        <endpoint address="http://localhost/Calculator"   
                  binding="wsHttpBinding"  
                  bindingConfiguration="InteropCertificateBinding"  
                  name="WSHttpBinding_ICalculator"  
                  contract="ServiceModel.ICalculator" />  
      </service>  
    </services>  
    <bindings>  
      <wsHttpBinding>  
        <binding name="InteropCertificateBinding">  
          <security mode="Message">  
            <message clientCredentialType="Certificate"  
                     negotiateServiceCredential="false"  
                     establishSecurityContext="false" />  
          </security>  
        </binding>  
      </wsHttpBinding>  
    </bindings>  
    <client />  
  </system.serviceModel>  
</configuration>  

The following code and configuration are meant to run independently. Do one of the following:

  • Create a stand-alone client using the code (and client code).

  • Create a client that does not define any endpoint addresses. Instead, use the client constructor that takes the configuration name as an argument. For example:

                CalculatorClient cc = new CalculatorClient("EndpointConfigurationName");
    

Code

The following code creates the client. The security mode is set to Message, and the client credential type is set to Certificate.

            // Create the binding.
            WSHttpBinding myBinding = new WSHttpBinding();
            myBinding.Security.Mode = SecurityMode.Message;
            myBinding.Security.Message.ClientCredentialType =
                MessageCredentialType.Certificate;

            // Disable credential negotiation and the establishment of 
            // a security context.
            myBinding.Security.Message.NegotiateServiceCredential = false;
            myBinding.Security.Message.EstablishSecurityContext = false;

            // Create the endpoint address. 
            EndpointAddress ea = new
                EndpointAddress("http://machineName/Calculator");

            // Create the client. 
            CalculatorClient cc =
                new CalculatorClient(myBinding, ea);

            // Specify a certificate to use for authenticating the client.
            cc.ClientCredentials.ClientCertificate.SetCertificate(
                StoreLocation.CurrentUser,
                StoreName.My,
                X509FindType.FindBySubjectName,
                "Cohowinery.com");

            // Specify a default certificate for the service.
            cc.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
                StoreLocation.CurrentUser,
                StoreName.TrustedPeople,
                X509FindType.FindBySubjectName,
                "Contoso.com");

            // Begin using the client.
            try
            {
                cc.Open();
                Console.WriteLine(cc.Add(200, 1111));
                Console.ReadLine();

                // Close the client.
                cc.Close();
            }

Configuration

The following configures the client. A client certificate must be specified using the <clientCertificate>. Also, the service certificate is specified using the <defaultCertificate>.

<?xml version="1.0" encoding="utf-8"?>  
<configuration>  
  <system.serviceModel>  
    <behaviors>  
      <endpointBehaviors>  
        <behavior name="ClientCredentialsBehavior">  
          <clientCredentials>  
            <clientCertificate findValue="Cohowinery.com"   
                 storeLocation="CurrentUser"  
                 storeName="My"  
                 x509FindType="FindBySubjectName" />  
            <serviceCertificate>  
              <defaultCertificate findValue="Contoso.com"   
                                  storeLocation="CurrentUser"  
                                  storeName="TrustedPeople"  
                                  x509FindType="FindBySubjectName" />  
            </serviceCertificate>  
          </clientCredentials>  
        </behavior>  
      </endpointBehaviors>  
    </behaviors>  
    <bindings>  
      <wsHttpBinding>  
        <binding name="WSHttpBinding_ICalculator" >  
          <security mode="Message">  
            <message clientCredentialType="Certificate"   
                     negotiateServiceCredential="false"  
                     establishSecurityContext="false" />  
          </security>  
        </binding>  
      </wsHttpBinding>  
    </bindings>  
    <client>  
      <endpoint address="http://machineName/Calculator"   
                behaviorConfiguration="ClientCredentialsBehavior"  
                binding="wsHttpBinding"   
                bindingConfiguration="WSHttpBinding_ICalculator"  
                contract="ICalculator"  
                name="WSHttpBinding_ICalculator">  
        <identity>  
          <certificate encodedValue="Encoded_Value_Not_Shown" />  
        </identity>  
      </endpoint>  
    </client>  
  </system.serviceModel>  
</configuration>  

Security Overview
Security Model for Windows Server App Fabric
How to: Create and Install Temporary Certificates in WCF for Transport Security During Development

Show: