configuring https endpoint with WCF self hosting - wcf

I have created basichttpendpoint with security mode="TransportWithMessageCredential" for my self hosted WCF service.
My server config has:
enter code here
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IViewerManager" maxBufferSize="655360000" maxReceivedMessageSize="655360000" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="SecureBehavior" name="Lumedx.ApolloLXPACS.ViewerServiceLibrary.ViewerManager">
<endpoint name="basicHTTP" address="https://localhost:5100/ViewerService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IViewerManager" contract="Lumedx.ApolloLXPACS.ServiceContracts.IViewerManager"/>
<host>
<baseAddresses>
<add baseAddress="https://localhost:5100/ViewerService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="HttpsBehavior">
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceCredentials>
<serviceCertificate findValue="RootCATest"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByIssuerName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
my windows client config has:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="priorityEndpoint1" value="basicHttpEndpoint"/>
<add key="maxCommunicationRetries" value="0"/>
</appSettings>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IViewerManager" maxBufferSize="655360000" maxReceivedMessageSize="655360000" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="basicHttpEndpoint" address="https://10.10.10.100:5100/ViewerService/" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IViewerManager" contract="Lumedx.ApolloLXPACS.ServiceContracts.IViewerManager" behaviorConfiguration="HttpsBehavior"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="HttpsBehavior">
<clientCredentials>
<clientCertificate findValue="RootCATest"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByIssuerName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<
I have installed and configured certificate.
I am connecting my windows client with the self hosted WCF service with https end points. I captured network traffic using wireshark. All I see in the network traffic is TCP packets between the server and client. When I follow the TCP stream the message does not seem to be encrypted.
What am I doing wrong here?

Security mode TransportWithMessageCredential encrypts transport (SSL) and leaves message body not encrypted.
Encryption is made using your certificate.
If you see not encrypted data one of the following scenarios happend:
Traffic for some reason is not encrypted with ssl
Wireshark has access to your certificate and encrypted traffic using it.
Is this looks similar to what you did? http://trycatch.be/blogs/decaluwet/archive/2009/04/08/decrypting-ssl-traffic-using-wireshark.aspx
In any case you should be safe if transport level encryption is enable and your certificate is not compromised.

Related

WCF throws exception that the server has rejected the client credentials, what is the default security mode for NetTCP in WCF

The WCF is deployed as a windows service in the server. And the client is a windows form applicaiton. When the client is interacting with the WCF server, is there any kind of authentication going on here?
I got how to resolve this here
I want to know what is the default security mode for NetTCP in WCF? I had nothing related with security in my config file as below. So what is the default?
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="BasicServiceBehavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="HCCNetTcpBinding" >
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="BasicServiceBehavior" name="HCC.SMS4.SERVICES.BASIC.MainServices">
<endpoint address="" binding="netTcpBinding" contract="HCC.SMS4.SERVICES.BASIC.IMainServices" bindingConfiguration="HCCNetTcpBinding" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://xxxx:44008/HCsmsBasicServices/"/>
<add baseAddress="net.tcp://xxxx:45008/HCsmsBasicServices/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="HCCNetTcpBinding" maxConnections="1000" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"
openTimeout="14:00:00" receiveTimeout="14:00:00" sendTimeout="14:00:00">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
The transport security mode of the NetTcpBinding is Transport and the ClientCredentialType is Windows. This is equivalent to the following settings.
<netTcpBinding>
<binding name="netTcp">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
So when you use the client proxy class to call the service, you could refer to the following code.
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
client.ClientCredentials.Windows.ClientCredential.UserName = "administrator";
client.ClientCredentials.Windows.ClientCredential.Password = "abcd1234!";
var result = client.SayHello();
https://learn.microsoft.com/en-us/dotnet/framework/wcf/system-provided-bindings
https://learn.microsoft.com/zh-cn/dotnet/framework/wcf/feature-details/bindings-and-security
Feel free to contact me if you have any questions.
WCF, its default authentication is Windows if there is none config about it.
Per Microsoft documentation for NetTcpBinding the default security is TLS with Windows security.

Moving WCF to HTTPS

My http based web service is working fine and I've been asked to move it to https (the certificates and stuff on IIS have already been done).
But I'm completely stuck on what I need to do. All the websites seem to show you what changes to make to the web.config file, but when I check mine it is nothing like these (e.g. there is no services element), and none of the sites mentioned what changes to the client config you make and they're all dated from 5 years ago or more.
When I check my client config file that calls the webservice it seems to have half the configuration entries that is supposed to be in the new web.config on the server.
Can anyone help?
CLIENT config file.
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMyService" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" useDefaultWebProxy="false" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://example.com/TestService/TestService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMyService" contract="Service.IMyService"
name="BasicHttpBinding_IMyService" />
</client>
</system.serviceModel>
</configuration>
SERVER WEB.CONFIG
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
I changed you settings so that is similar to my settings. You should use the values that are specific for your server:
I have added
<security mode="Transport"></security>
and
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceCredentials>
<serviceCertificate findValue="<thumbprint>" storeLocation="LocalMachine"
storeName="My" x509FindType="FindByThumbprint" />
</serviceCredentials>
this is needed for specifying the certificate and that is should use transport security mode.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport"></security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceCredentials>
<serviceCertificate findValue="<thumbprint>" storeLocation="LocalMachine"
storeName="My" x509FindType="FindByThumbprint" />
</serviceCredentials>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
make sure that you change the value to your thumbprint of the certificate. You should also make sure that the certificate is in the correct store.
This is just guessing from my side. Take this with a grain of salt because I have not tested it with you configuration.

Implement transport security on my WCF service with custombinding on HTTP

I am new to WCF security . I am trying to implement transport security on my WCF service. We are using custombinding on HTTP. Can someone please suggest how can we do that?
<customBinding>
<binding name="CustomBinding">
<binaryMessageEncoding/>
<httpTransport allowCookies="true" maxReceivedMessageSize="2000000000" maxBufferSize="2000000000" maxBufferPoolSize="2000000000"/>
</binding>
</customBinding>
You're going to want to use Certificates to achieve transport-level security.
You can use this tutorial (below) on how to create "test" certs; for production I'd advise either issuing a cert using your own company's internal CA (if they have one) or use a trusted provider (Symantec, GlobalSign, etc).
http://msdn.microsoft.com/en-us/library/bfsktky3(v=vs.110).aspx
You can use this tutorial (below) on how to install the certificate(s) on the box(es).
http://msdn.microsoft.com/en-us/library/bb950259(v=bts.10).aspx
As far as the service app.config -- it should be something like the below:
<system.serviceModel>
<services>
<service name="YourServiceNameGoesHere" behaviorConfiguration="MyCustomBehavior">
<endpoint address="YourAddressGoesHere" binding="customBinding" contract="YourIContractNameGoesHere" bindingConfiguration="MyCustomBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyCustomBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" trustedStoreLocation="LocalMachine" />
</clientCertificate>
<serviceCertificate findValue="YourCertNameGoesHere" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="MyCustomBinding">
<security authenticationMode="CertificateOverTransport" />
<httpsTransport />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
As far as the client app.config -- it should be something like the below:
<system.serviceModel>
<client>
<endpoint address="YourAddressGoesHere" binding="customBinding" bindingConfiguration="MyCustomBinding" behaviorConfiguration="MyCustomBehavior" contract="YourIContractNameGoesHere" name="YourClientNameGoesHere" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="MyCustomBehavior">
<clientCredentials>
<clientCertificate findValue="YourCertNameGoesHere" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="MyCustomBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
<httpsTransport />
</binding>
</customBinding>
</bindings>
</system.serviceModel>

Transfer large amount of data in WCF service

I have created a web service in WCF which returns more than 54000 data-rows with 10 data in each row. I have used the wsHttpBinding for communication. The service works well with less data (i.e. 2000 rows) but it bombs out when attempting to send large record set with 50000+ rows(~2MB). The exception message is like this
An error occurred while receiving the HTTP response to http://localhost:9002/MyService.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.
Please don't tell me to use pagination on the client side - I know that it will solve the problem. But I need the whole chunk of data in the client-end.
My service configuration on server is as
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyWsHttpBinding" />
</wsHttpBinding>
</bindings>
<services>
<service name="AdminService">
<endpoint address="AdminSrv"
binding="wsHttpBinding"
contract="IAdminService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="/Bus/IRfotoWCF" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
</system.serviceModel>
My client configuration is as
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IAdminService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/TestService/AdminService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAdminService"
contract="IAdminService" name="BasicHttpBinding_IAdminService" />
</client>
</system.serviceModel>
Would someone help me out with excact configuration both in the client and server side. Even if i need to change binding from wsHttpBinding to netTcpBinding - i have no problem doing that. Thanks in advance.
After a lot of investigation finnally i got the solution. Actually a number of things need to be changed.
The following changes needed to be done in Server-side.
First I had to set a maxRequestLength to a larger value in my httpRuntime element to run the request for longer period.
<system.web>
<httpRuntime maxRequestLength="102400" />
</system.web>
Second i introduced netTcpBinding binnding with custom changes on maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize with a large value of 2147483647.
<binding name="myNetTcpBinding"
maxBufferPoolSize="2147483647"
maxBufferSize="524288"
maxReceivedMessageSize="2147483647">
Third add maxItemsInObjectGraph in both of the serviceBehaviors and endpointBehaviors like bellow (dont forget to mention the behaviour names in the service and endpoint node)
<behaviors>
<serviceBehaviors>
<behavior name="myNetTcpBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="myNetTcpEndPointBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</endpointBehaviors>
</behaviors>
Finally my server configuration looks like this
<system.web>
<httpRuntime maxRequestLength="102400" />
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyWsHttpBinding" />
</wsHttpBinding>
<netTcpBinding>
<binding name="myNetTcpBinding"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:01:00"
transactionFlow="false"
transferMode="Buffered"
transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard"
listenBacklog="10"
maxBufferPoolSize="2147483647"
maxBufferSize="524288"
maxConnections="10"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32"
maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
<reliableSession ordered="true"
inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="AdminService" behaviorConfiguration="myNetTcpBehaviour">
<endpoint address="AdminSrv"
binding="netTcpBinding"
bindingConfiguration="myNetTcpBinding"
contract="IAdminService"
behaviorConfiguration="myNetTcpEndPointBehaviour"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="/Bus/IRfotoWCF" />
</baseAddresses>
</host>
</service>
<behaviors>
<serviceBehaviors>
<behavior name="myNetTcpBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="myNetTcpEndPointBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
</system.serviceModel>
Now on the client-side configuratioin you need to change the maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
and also you need to add maxItemsInObjectGraph="2147483647" in endpoint behaviour configuration.
<endpointBehaviors>
<behavior name="myEndPointBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
Now i can transmit 30000 rows within 5.30 min where the query executed for 10 sec so the transmission time is 5.20 min - still a lot.
Feel free to comment and any suggestion for improvement.
If you look at the binding details they do not match entirely on the server and that of the client side. The attributes for maxBufferSize, maxBufferPoolSize, maxReceivedMessageSize are to be defined in the server side as well. And then you need to put the values according to the size you are looking at.
Instead of using for loop over WCF for bulky data , Use user defined table type ( if you are using SQL) . It will reduce the time from 6 min to 15-20 sec.

Authentication a WCF Request via Client Certificate over HTTPS

I've been struggling with the configuration for this blasted WCF service for the past week, and I'm slowing beginning to suspect that what I'm trying to do is just not possible, despite the documentation.
Quite simply, I want to have a WCF service require a client certificate (which the server will have in its cert store), and then access that identity with System.ServiceModel.ServiceSecurityContext. Additionally, this needs to use transport security.
Here's my server config:
<system.serviceModel>
<services>
<service behaviorConfiguration="requireCertificate" name="Server.CXPClient">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="PartnerComm.ContentXpert.Server.ICXPClient" />
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="requireCertificate">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" maxBufferPoolSize="5242880" maxReceivedMessageSize="5242880">
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
Here's my client config:
<system.serviceModel>
<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="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/"
binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="ClientCertificateBehavior"
contract="ContentXPertServer.ICXPClient" name="wsHttpEndpoint" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
The code all works perfectly when security mode='None' over http, but of course, there's no authentication, and nothing in System.ServiceModel.ServiceSecurityContext. I've tried dozens of variations on all of these elements, and it all ends up inevitably with the request throwing an exception "An existing connection was forcibly closed by the remote host".
I'm using a self-signed cert "CyberdyneIndustries", whose CA cert I've added to the trusted CA store. The cert checks out when I view it. I've gone through the hell of http namespace management, and solved those problems as well. It simply looks like WCF doesn't really support this...please tell me I'm wrong.
TIA.
Ultimately, I decided to try message security, to see if that would shed some light on the situation - it did, and I'm going to cut my losses and go with that. So, there's no definitive answer to this.
Implementing message security did, however, expose a BIG problem, and this may have been the root of the transport security problem. There is a piece of poison documentation from MSDN:
http://msdn.microsoft.com/en-us/library/ff650751.aspx
On this page, the command to create the self-signed cert is as follows:
makecert -sk MyKeyName -iv
RootCaClientTest.pvk -n
"CN=tempClientcert" -ic
RootCaClientTest.cer -sr currentuser
-ss my -sky signature -pe
The argument "signature" should instead be "exchange". Once I regenerated all my certs, message security started working. One big takeaway from all of this is that if you're wanting to implement transport security, get message security working first, because the error messages you get from the system are much more descriptive.
Does the SSL handshake succeed? Enable SChannel logging to troubleshoot the SSL layer. See this old KB article: How to enable Schannel event logging in IIS. Although is an KB for W2K and XP, the steps to enable SChannel logging are the same and still valid on newer systems. With the logging enabled you'll be able to determine why is SSL rejecting the certificate.
I know this is 3 years old, but for those who might still be interested...
I'm in the process of learning WCF (security among other things) and was able to get things working properly with netTcpBinding (presumably, this will work for WsHttpBindings as well) using Transport security mode with a clientCredentialType="Certificate" (and, protectionLevel="EncryptAndSign", though that wasn't germane to the issue).
I did encounter the force connection close error from the server-side too, but discovered I was missing one piece of configuration. It's all working now.
Here's my server-side config:
<configuration>
<system.serviceModel>
<services>
<service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<serviceCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="TcpCertSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
And my client-side configuration:
<configuration>
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding"
bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService"
behaviorConfiguration="MyServiceBehavior">
<identity>
<dns value="MyServiceCert" />
</identity>
</endpoint>
</client>
<bindings>
<netTcpBinding>
<binding name="TcpCertSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" />
</serviceCertificate>
<clientCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I created a certificate chain for the server (self-signed Trusted Root certificate + a certificate built using that root) using the technique described here and stored both the Root cert and child cert in the certificate store of my server host machine. And, finally, I imported that server certificate + public key into the cert store on my client host machine (in LocalMachine/TrustedPeople).
WsHttpBinding DOES support certificate authentication for transport security.
There can be a few things wrong:
Did you add both certificates to your store? CyberdyneIndustries as well a CA that you used to sign it? CA should be in "Trusted Root Certification Authorities"
Also, i've done this self-hosted, never in Visual Studio Dev server. Try to host your service in IIS at least. I am not sure if VS Dev server supports certificates.
Try to turn off service authentication. So the client doesn't have to authenticate the service. I don't know if you want this in your app or not but just for testing so we can rule that out
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" />
<serviceCertificate>
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>