WCF service config exception “it is likely that certificate may not have a private key…”

soapwcfws-security

After my previous question – WCF client for consuming ASMX service with WS-Security , I need to configure a WCF service that will receive SOAP requests using WS-Security (request sample can be found in the link).

This is my config file:

  <system.serviceModel>
    <services>
      <service name="Service.Service1" behaviorConfiguration="customBindingBehavior">
        <endpoint address="http://localhost/Service1.svc" 
                  binding="customBinding"
                  bindingConfiguration="NewBinding0" 
                  name="ServiceEndpoint"
                  contract="Service.Contracts.IService1" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="customBindingBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceMetadata httpGetEnabled="true" />
          <serviceCredentials>
            <serviceCertificate findValue="xxx" x509FindType="FindByThumbprint" storeLocation="LocalMachine" storeName="My" />
            <clientCertificate>
              <certificate findValue="yyy" x509FindType="FindByThumbprint" storeLocation="LocalMachine" storeName="TrustedPeople" />
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <customBinding>
        <binding name="NewBinding0">
          <textMessageEncoding messageVersion="Soap11WSAddressingAugust2004" />
          <security authenticationMode="MutualCertificate">
            <secureConversationBootstrap />
          </security>
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>
  </system.serviceModel>
</configuration>

The service certificate contains private key in order to sign the response.

The client certificate contains only the corresponding public key of the client's private key that was used to sign the request.

I get the following exception associated with the service certificate:

"The certificate 'CN=xxxxxx' must have a private key that is capable of key exchange. The process must have access rights for the private key."

How can I fix it?

Thanks in advance!

EDIT:

The exception I get:

System.ArgumentException: It is likely that certificate 'CN=xxx' may not have a private key that is capable of key exchange or the process may not have access rights for the private key.
at System.ServiceModel.Security.SecurityUtils.EnsureCertificateCanDoKeyExchange(X509Certificate2 certificate)
at System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateServerX509TokenProvider()
at System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateLocalSecurityTokenProvider(RecipientServiceModelSecurityTokenRequirement recipientRequirement)
at System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateSecurityTokenProvider(SecurityTokenRequirement requirement)
at System.ServiceModel.Security.AsymmetricSecurityProtocolFactory.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecurityProtocolFactory.Open(Boolean actAsInitiator, TimeSpan timeout)
at System.ServiceModel.Security.SecurityListenerSettingsLifetimeManager.Open(TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelListener`1.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
at Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)

Best Answer

Not clear from the message if the error is on the server or client cert. Anyway you only need to configure the server cert. The client cert wil be validated according to a policy you can specify in the behavior.

you can use this binding:

<customBinding>
                <binding name="NewBinding0">
                    <textMessageEncoding messageVersion="Soap11" />
                    <security authenticationMode="MutualCertificate" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
                        <secureConversationBootstrap />
                    </security>
                    <httpTransport />
                </binding>
</customBinding>

also make sure to decorate the service contract with:

[ServiceContract(ProtectionLevel=System.Net.ProtectionLevel.Sign)]