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.
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.
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.
Exported the TempCert certificate and private key.
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.
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.
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.
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)
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".
Related
I am trying to call an existing bridge from Azure BizTalk Service, but getting following error:
Could not establish trust relationship for the SSL/TLS secure channel with authority 'domain-name'.
I have tried all possible configurations of WCF bindings but none of them work, the last configuration is as follows:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="ServiceBinding">
<security mode="Transport" />
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ServiceCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="CN=certificate-name"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<clear />
<endpoint address="https://bridge-url" binding="wsHttpBinding" contract="System.ServiceModel.Routing.ISimplexDatagramRouter" name="OneWayExternalServiceEndpointReference2" bindingConfiguration="ServiceBinding" behaviorConfiguration="ServiceCredentialBehavior">
<identity>
<certificate encodedValue="encoded-value" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Could you please advise if I am missing something very obvious, will be appreciated.
Is your certificate self signed ? if yes then you must :
Create a self-signed certificate to be used to encrypt an SSL channel
Upload a certificate to Windows Azure using the Windows Azure Management portal
Enable an HTTPS endpoint on a Windows Azure web role
All detailed instructions are available here
[How To: Enable SSL with a Self-Signed Certificate on Windows Azure][1]
If your certificated is not self signed then I Think you must add the certificate to your local root certificate authority
I have a set of WCF Services on one server that is being called from my website on another server. Without any security and just basicHttpBinding, this works just fine. Now I want to completely secure the same setup using SSL Transport with a self-signed certificate.
First I tried to use IIS on the Services Server to create a self-signed certificate, but the issue is that it is always creating the cert with the subject in mixed case but the url is lower case. Not sure if that will cause an issue, but I didn't succeed with it.
So I used makecert to (1) create a root cert that I then installed the *.cer file on the client server and service server into the Root CA stores and then (2) created another cert, using the root as the CA, that will be used for signing. I copied this one *.pfx and installed into the Personal store of the LocalComputer for both servers again.
So, now on my Services server, I went into IIS and setup the binding for 443 using the client cert. Then I selected my virtual directory and setup SSL requiring SSL and then selecting 'Required' for Client Certificates.
Now, if I just try to bring up the virtual directory in IE, using https and the full name as it shows in the cert, I get 403.7. I can't seem to get passed this error.
If I try to hit this virtual directory from the website server, I get a plain 403.
If I change my IIS setup to 'Accept' client certs instead of 'Require', the I can browse to my services on both boxes.
Somethings missing...but can't seem to find it.
Update:
Ok, so I created a one-page website and locked it down Requiring the same cert and was able to install that cert into IE on a client and hit the website. Finally, after installing the cert into IT, it allowed me to browse my Services virtual directory and even bring up the page on one of my services.
Question 1: When installing the server cert, I installed the private key version on both Server and Client machine into the LocalMachine -> Personal location. Is this correct or should I just install the public key into the client? It seems to be working.
Still problem - when making a WCF call now I'm getting the following:
SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'myserver.mydomain.com'.
Here's my server configuration:
<system.serviceModel>
<protocolMapping>
<add scheme="https" binding="basicHttpBinding"/>
</protocolMapping>
<bindings>
<basicHttpBinding>
<binding name="SecureCertBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyName.MyService" behaviorConfiguration="SecureBehavior">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="SecureCertBinding" name="SecureAlertService" contract="MyName.IMyService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="myserver.mydomain.com" storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Here's my client configuration:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SmallData" maxReceivedMessageSize="5000000">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="524288" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="SecureEndpoint">
<clientCredentials>
<clientCertificate findValue="myserver.mydomain.com" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="https://myserver.mydomain.com/Services/MyService.svc" binding="basicHttpBinding" behaviorConfiguration="SecureEndpoint"
bindingConfiguration="BasicHttpBinding_SmallData" contract="MyName.IMyService" name="BasicHttpBinding_IMyService"/>
</client>
</system.serviceModel>
How can I tell if the client is sending the certificate with the request?
Got it!! Finally.
I restarted the whole process, including creating new certs and all. Once I got passed the part where IE couldn't even navigate to the Services Virtual Directory, I knew from that point I was mainly up against WCF.
I use a service account on my Services Server for the application pool that has proper authority to the database. This way my connection strings are Windows Auth.
Make sure this service account has Full Permissions to the Cert (Snap-in...Manage Private Keys).
After doing this, I was still getting an error but I found an entry in my System Event Logs that stated an error occurred when trying to retrieve the private key from a cert. This finally helped.
My website (aka...Services client) is still running the application pool with ApplicationPoolIdentity. If this is the case:
Make sure to give the group 'IIS_Usrs' Full Permissions to the Cert.
Bingo...everything worked from this point forward...complete security.
I’m trying to setup a security transport using certificates over a SSL service.
The service is installed over IIS, I have configured it using a “MyLaptop” certificate (stored on local machine/Personal) validated by a self-signed certificate (“My Root CA” certificate – stored on local machine Trusted Root Certification Authorities). Everything seems to be OK with the service; I can access it using the Internet Explorer.
On the server side the web.config looks like
<behaviors>
<serviceBehaviors>
<behavior name="EchoServiceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MutualSslBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="EchoServiceBehavior" name="HttpsBindingDemo.EchoService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MutualSslBinding"
contract="HttpsBindingDemo.IEchoService">
<identity>
<dns value="MyLaptop" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="https://MyLaptop:12643/EchoService/" />
</baseAddresses>
</host>
</service>
On the client side I have installed a new certificate “MyClient” (stored on CurrentUser/Personal) validated by the same “My Root CA” certificate.
On the client side the app.config looks like
<behaviors>
<endpointBehaviors>
<behavior name="EchoClientBehavior">
<clientCredentials>
<clientCertificate findValue="MyClient" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEchoService">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://MyLaptop:12643/EchoService/EchoService.svc" behaviorConfiguration="EchoClientBehavior"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEchoService"
contract="SecuredServices.IEchoService" name="WSHttpBinding_IEchoService">
<identity>
<dns value="MyLaptop" />
</identity>
</endpoint>
</client>
Every time when trying to execute the operations of the EchoService.svc I’m receiving the error below:
“The HTTP request was forbidden with client authentication scheme 'Anonymous'.”
Enabling the service’s log I found that first exception message is in fact “Client certificate is required. No certificate was found in the request. This might be because the client certificate could not be successfully validated by the operating system or IIS. For information on how to bypass those validations and use a custom X509CertificateValidator in WCF please see http://go.microsoft.com/fwlink/?LinkId=208540.”.
Could you please help me to understand how to correctly configure the service to avoid the described errors?
Thank you!
It looks like you are most likely missing the serviceCertificate tag inside of your serviceCredentials tag in your service behavior. Try adding this and it should resolve the issue. Each time I use certificates with a WCF service I always have to specify in the config what certificate the service should be using.
http://msdn.microsoft.com/en-us/library/ms731340%28v=vs.110%29.aspx
When you import client cert to your personal store, try to import using pfx file and specifying the password
The client machine has the "TicketSalesClient" certificate in "My" storage of current user and the "TicketSalesServer" certificate in "TrustedPeople" storage of current user. The server machine has "TicketSalesClient" certificate in "TrustedPeople" storage of local machine and the "TicketSalesServer" certificate in "My" storage of local machine.
The service runs under IIS 7. Below is the web.config file:
<system.serviceModel>
<services>
<service behaviorConfiguration="secureBehavior" name="InternetRailwayTicketSales.TicketSalesImplementations.TicketSalesService">
<endpoint address="TicketSalesService"
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding" contract="InternetRailwayTicketSales.TicketSalesInterface.ITicketSales" />
<endpoint address="TicketSalesServiceSecureMex"
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:443/TicketSales/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="secureBehavior">
<serviceThrottling maxConcurrentInstances="5000" maxConcurrentSessions="5000" />
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="True" />
<serviceCredentials>
<serviceCertificate findValue="TicketSalesServer"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
The service in IIS is configured for SSL and certificate requiring.
1)Now when I try to add service reference in the client I receieve: "The HTTP request was forbidden with client authentication scheme 'Anonymous'. The remote server returned an error: (403) Forbidden."
2)If I try to request the metadata endpoint using browser I firstly apply the SSL certificate and then receieve an error that "The credentials do not give the right to view this directory or page." As I understand this is because I can't give the client credentials through the browser.
3)I tried to use svcutil with configuration file which contains client credentials:
<configuration>
<system.serviceModel>
<client>
<endpoint
behaviorConfiguration="ClientCertificateBehavior"
binding="basicHttpBinding"
bindingConfiguration="Binding1"
contract="IMetadataExchange"
name="https" />
</client>
<bindings>
<basicHttpBinding>
<binding name="Binding1">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate findValue="TicketSalesClient"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
And then:
svcutil https://veryLongAddress.svc?wsdl /config:svcutilConf.config
And the response is that the "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"
So what am I doing wrong?
Seems like your certificates installation is fine. Can you try as shown below and see the output. Try to browse to the service from IE and you should be able to see the service and its wsdl.
Go to IE and then
Tools --> Internet Options --> Security --> Internet --> Custom Level
Tools --> Internet Options --> Security --> Intranet --> Custom Level
Now scroll down to Misc section to find the option "Dont Prompt for client certificate selection when no certificate is present or only one certificate is present" to Diable.
Now restart IE and browse to the service and IE should ask you to select a client certificate from the personal store and you need to select mvc.localhost.
If TicketSalesClient cert is not visible then your client certificate is not in the appropriate store.
The reason for this is that the file you are using to install the certificates do matter as well as the purpose for which the certificate has been created. You can find the purpose of each certificate when you double click them in the certificate store you have a column that is called Intended Purpose. Make sure its for your client certificate.
When hosting the service in IIS all endpoints must have the same transport security configuration. I played with this before and I ended with redefining binding for WSDL GET (yes it has also internal binding defined). So modify your bindings on service to:
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
<customBinding>
<binding name="wsdlBinding">
<textMessageEncoding messageVersion="None" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
And in service behaviors use:
<serviceMetadata httpsGetEnabled="true"
httpsGetBinding="customBinding"
httpsGetBindingConfiguration="wsdlBinding" />
This should force WSDL get to require client certificate and it "should" work from browser (unless there is some other problem).
When we host WCF service in IIS with security type transport and client credential type certificate, Then put your client certificate on Root store and enable anonymous authentication in IIS. Enable anonymous authentication in IIS But most important, add your certificate to root store.
I need to use an x509 certificate to get secure message level authentication from a rich client via the internet to a secure WCF Web Service.
Specifically, I am looking for a working step-by-step guide to setup, configuration, coding, and deployment, including creating a 'dev' certificate, installing it, and obtaining a 'real' certificate for production.
The following steps are a guide to get you started:
1) Firstly, you need a Root Authority to generate your client and server certificates. You can either use an external Authority Provider (e.g. Verisign) or you can generate your own using something like Microsoft Certificate Server.
To generate a development Root Authority certificate you can use the "makecert" tool that comes with Visual Studio, e.g.
makecert -n "CN=MyRootCA" -r -sv RootCA.pvk RootCA.cer
2) You then need to request/generate your client and server certificates. Both types of certificates can be installed as local machine certificates and both need to be signed using the same root authority. You can request client certificates from a Microsoft Certificate Server's web interface, e.g. http://mycertserver/certsrv.
To generate a development client certificate for each machine you can use "makecert" again. Note that the client certificates are signed with development Root Authority certificate created in step 1.
makecert -pe -n "CN=MyCert" -ss my -sky exchange -sk MyCert
-iv MyRootCA.pvk -ic MyRootCA.cer -sr localmachine MyCert.cer
This will install the certificate on the machine on which the command is run, into the Personal certificates folder in the Local Machine store.
In order for the server to trust the client certificates you will need to install the development Root Authority certificate in the server's Trusted Root Certificate Authorities store (use the mmc Certificates snap-in to do this). The clients should also have the root certificate installed in the same way so that they trust their own certificates.
3) Configure you WCF service to require client authentication using a certificate (e.g. via the web.config).
<services>
<service
name="TestService"
behaviorConfiguration="wsHttpCertificateBehavior">
<endpoint name="TestEndPoint"
address=""
binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
contract="TestService.IMyContract">
<identity>
<dns value=""/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<behavior name="wsHttpCertificateBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceCredentials>
<clientCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"
revocationMode="NoCheck"/>
</clientCertificate>
<serverCertificate findValue="CN=MyCert"/>
</serviceCredentials>
</behavior>
</behaviors>
4) Now configure the caller (e.g. via the app.config).
<client>
<endpoint name="wsHttpBinding"
address="https://localhost/TestService/TestService.svc"
binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding"
behaviorConfiguration="wsHttpCertificateBehavior"
contract="TestService.IMyContract">
<identity>
<dns value="MyCert"/>
</identity>
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBinding">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="wsHttpCertificateBehavior">
<clientCredentials>
<clientCertificate findValue="MyCert" storeLocation="LocalMachine"/>
<serviceCertificate>
<authentication
certificateValidationMode="PeerOrChainTrust"
revocationMode="NoCheck"
trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
I'd recommend reading the WCF Security guidance from Microsoft
This deals with this scenario as well as many others
http://www.codeplex.com/WCFSecurityGuide/
edit: now at https://archive.codeplex.com/?p=wcfsecurityguide