WCF Exception - The client certificate is not provided

10,570

Solution 1

The last error message indicates that your server is requesting a client certificate from the client (the server has to ask), and the client is providing a certificate, but the server is not able to determine whether the client certificate is valid based on information available on the server machine.

Since you are using self-signed certificates (not CA issued certificates), you need to tell the server how to validate the client certificates. You may need to install the client certificates in the server's My/LocalMachine/Trusted People cert store so that WCF's default certificate validation can find them, or implement your own custom client certificate validator on the server. (See WebHttpBinding.Credentials.ClientCertificate.Authentication.CertificateValidationMode and WebHttpBinding.Credentials.ClientCertificate.Authentication.CustomCertificateValidator)

Solution 2

I did notice that in your endpoint definition, you did not refer to the behavior that you defined. It looks as if you are doing the equivalent, by-hand via some code. It might be simpler to just wire-it-up in the config.

I would expect your endpoint to look (more) like this:

      <endpoint address="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/"
          binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint"
          contract="SBSWCFService.IOperations" name="wsHttpEndpoint"
          behaviorConfiguration="EndpointBehavior">
          <identity>
              <dns value="localhost" />
          </identity>
      </endpoint>

This was the solution, when I was getting the error "The client certificate is not provided. Specify a client certificate in ClientCredentials".

Share:
10,570
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    WCF Exception - The client certificate is not provided. Specify a client certificate in ClientCredentials.

    After reading most of what I have been able to find on this subject, and attempting many different options, I find I don’t have any more hair to pull, and hence this post.

    I wish to use SSL with a self-hosted WCF service, having security mode as TransportWithMessageCredential with HTTP transport. I am using 2 dev machines and testing over a LAN.

    As mentioned above, I have read and meticulously followed just about every example which demonstrates this, yet somehow still have issues with the certificates.

    As far as the certificates are concerned, I have tried a number of things.

    The main jist of what I did was to follow what is given in http://msdn.microsoft.com/en-us/library/ff647171.aspx

    I also used “How to: Use Certificate Authentication and Message Security in WCF Calling from Windows Forms” in http://msdn.microsoft.com/en-us/library/ff648360.aspx as a basic guide.

    I first tested the service and client using basicHttpBinding over Http in order to verify things.

    I then made changes for wsHttpBinding, SSL, and Certificates.

    When I “Add Service Reference” on the client dev PC, I receive an error as follows:

    • Window Titled -

    Security Alert

    Visual Studio has detected a problem with the site's security certificate.

    Issued By: RootCATest Issued to: TempCert Certificate is valid from---

    The security certificate issued by a company is not in the untrust list. It might be trustable.

    The security certificate date is valid.

    The security certificate for host 'TempCert' does not match the name of the page you are trying to view.

    • Do you want to proceed? -

    If I click “Yes” to proceed, and run the client code, an InvalidOperationException occurs with the following message.

    “The client certificate is not provided. Specify a client certificate in ClientCredentials.”

    The Service config is as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <behaviors>
                <serviceBehaviors>
                    <behavior name="ServiceBehavior">
                        <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
                        <serviceDebug includeExceptionDetailInFaults="true" />
                        <serviceCredentials>
                            <serviceCertificate findValue="CN=TempCert" 
                                                storeLocation="LocalMachine"
                                                storeName="My" />
                        </serviceCredentials>
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <bindings>
              <wsHttpBinding>
                <binding name="wsHttpEndpointBinding">
                  <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="Certificate" />
                  </security>
                </binding>
              </wsHttpBinding>
            </bindings>      
            <services>
                <service name="SBSWCFServiceHost.Operations" 
                         behaviorConfiguration="ServiceBehavior">
                    <endpoint name="wsHttpEndpoint"
                              address=""
                              binding="wsHttpBinding"
                              bindingConfiguration="wsHttpEndpointBinding"
                              contract="SBSWCFServiceHost.IOperations" >
                        <identity>
                            <dns value="localhost" />
                        </identity>
                    </endpoint>                          
                    <endpoint name="mexHttpEndpoint"
                              address="mex"
                              binding="mexHttpsBinding"
                              contract="IMetadataExchange" >
                    </endpoint>
                    <host>
                        <baseAddresses>
                            <add baseAddress="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
        </system.serviceModel>
    </configuration>
    

    The client config is as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <behaviors>
                <endpointBehaviors>
                    <behavior name="EndpointBehavior">
                        <clientCredentials>
                            <clientCertificate storeLocation="LocalMachine"
                                               storeName="My"
                                               x509FindType="FindByThumbprint"
                                               findValue="e4c87a961f796be6b6cab59c3760e43ffb6e941d"/>
                        </clientCredentials>
                  </behavior>
                </endpointBehaviors>
            </behaviors>      
            <bindings>
                <wsHttpBinding>
                    <binding name="wsHttpEndpoint" 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="TransportWithMessageCredential">
                            <transport clientCredentialType="None" proxyCredentialType="None"
                                realm="" />
                            <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                                algorithmSuite="Default" />
                        </security>
                    </binding>
                </wsHttpBinding>
            </bindings>
            <client>
              <endpoint address="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/"
                  binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint"
                  contract="SBSWCFService.IOperations" name="wsHttpEndpoint">
                  <identity>
                      <dns value="localhost" />
                  </identity>
              </endpoint>
            </client>
        </system.serviceModel>
    </configuration>
    

    The following is a Summary of the tasks I performed, based on the contents of numerous posts and documents.

    1. Created a self-signed CA certificate (named RootCATest) on the server, and placed it in the Trusted Root Certification Authorities Certificates folder of the Local Computer.

    2. Created a certificate which is signed by the RootCATest certificate (named TempCert), on the server, and placed it in the Personal Certificates folder of the Local Computer.

    3. Exported the TempCert certificate and private key.

    4. Copied the TempCert .cer and .pvk files to the client machine, and imported the TempCert Certificate into the Personal Certificates folder of the Local Computer.

    5. Executed ICalcs.exe [private key path] /grant "NT AUTHORITY\NETWORK SERVICE":R on the server machine, using the path to the private key for the TempCert certificate.

    6. Executed netsh http add sslcert ipport=o.o.o.o:8003 certhash=[TempCert thumbprint] appid=[{application id}] on the server machine

    I believe I am close to getting this working.

    It seems pretty obvious that the app is not happy with the TempCert certificate, yet I have not been able to resolve this, and am pretty much stuck.

    Any assistance with respect to any problems in the given configurations, the steps I have followed in order to put the correct certificates in place, and those used to add access permissions and the sslcert entry, will be greatly appreciated.

    Many thanks.

    After some further experimentation, I have noticed additional behavior.

    Steps taken are as follows:

    I deleted both client and server certificates, and recreated them in accordance with ....codeproject.com/Articles/36683/9-simple-steps-to-enable-x-509-certificates-on-wcf

    I added the new sslcert using netsh. I then exported the client certificate from the server and imported it into the client store.

    I modified the service app.config with the new certificates info, and started the service.

    I modified the client app.config as follows:

    <endpointBehaviors>
      <behavior name="EndpointBehavior">
        <clientCredentials>
          <clientCertificate storeLocation="LocalMachine" storeName="My"  x509FindType="FindBySubjectName" findValue="WCFClient" />
          <serviceCertificate>
            <authentication certificateValidationMode="PeerTrust" />
          </serviceCertificate>
        </clientCredentials>
      </behavior>
    </endpointBehaviors>
    

    I updated the Service Reference. The update procedure once again issued a Security Alert as before.

    I then executed the client, and received this error:

    "The client certificate is not provided. Specify a client certificate in ClientCredentials."

    I then set a breakpoint on "client = new WCFService.Client();" and checked the "client" instance. The value of client.ClientCredentials.ClientCertificate.Certificate = null.

    I then added the following in code after "client = new WCFService.Client();":

    X509Store store = new X509Store("My", StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
    X509Certificate2Collection collection = (X509Certificate2Collection) store.Certificates;
    foreach (X509Certificate2 x509 in collection)
    {
    if (x509.Thumbprint == "236D7D4AD95753B8F22D3781D61AACB45518E1B5")
    {
        client.ClientCredentials.ClientCertificate.SetCertificate(
            x509.SubjectName.Name, store.Location, StoreName.My);
    }
    }
    

    After execution of this code, client.ClientCredentials.ClientCertificate.Certificate contained the certificate.

    When then executing "client.Open();" , an exception is thrown with the following contents.

    The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. The remote certificate is invalid according to the validation procedure. Could not establish trust relationship for the SSL/TLS secure channel with authority

    If anyone with knowledge of what may be happening here could shed some light on this I will be very grateful.