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. 
            Dim binding As 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.
            Dim httpUri As New Uri("http://localhost/Calculator")
            
            ' Create the service host.
            Dim myServiceHost As New ServiceHost(GetType(ServiceModel.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(GetType(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:

                Dim cc As 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.
            Dim myBinding As 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. 
            Dim ea As New EndpointAddress("http://localhost/Calculator")
            
            ' Create the client. 
            Dim cc As 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(100, 11))
                Console.ReadLine()

                ' Close the client.
                cc.Close()
            Catch tex As TimeoutException
                Console.WriteLine(tex.Message)
                cc.Abort()
            Catch cex As CommunicationException
                Console.WriteLine(cex.Message)
                cc.Abort()
            Finally
                Console.WriteLine("Closed the client")
                Console.ReadLine()
            End Try

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: