I have a self-hosted wcf service which uses wsHttpBinding with Transport security. I want the service to authenticate a client using a certificate.
When the client communicates with the service using clientCredentialsType set to 'None' everything works fine. The certificate was created with OpenSSL (self-signed) and registered with netsh on a specific port. The name of the certificate is DomainName (machine name in my case).
Update
I have created certificates for both client and server and placed them in each others Trusted Root stores (server certificate in client's store and vice-versa).
I've gone over a lot of articles and other questions at SOF but even the ones that look relevant couldn't help me resolve the issue.
Current Configuration
Service
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" httpsHelpPageEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="httpsBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" sendTimeout="01:00:00">
<security mode="Transport" >
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="serviceBehavior" name="Service">
<endpoint binding="wsHttpBinding" bindingConfiguration="httpsBinding" contract="SomeNamespace.IService"/>
<host>
<baseAddresses>
<add baseAddress="https://domain:port/Something/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Client
<system.serviceModel>
<client>
<endpoint address="https://domain:port/Something/"
behaviorConfiguration="endpointCredentialBehavior"
binding="wsHttpBinding"
bindingConfiguration="Binding"
contract="SomeNamespace.IService"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="DomainName"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="Binding">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
I get the following exception:
System.ServiceModel.Security.MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'. ---> System.Net.WebException: The remote server returned an error: (403) Forbidden. at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
There is one more thing we need to do. We should make their certificate trusted by each other. the server’s certificate must be trusted by the client and the client’s certificate must be trusted by the server.
Please refer to the official document with regards to this issue.
Specifically, the server certificate is installed in the client Trusted Root Certification Authorities, the client certificate is installed in the server Trusted Root Certificate Authorities. It is best to use a local machine certificate store. We could check the certificate by using Certlm.msc command.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
For some special certificates created by other special tools, such as PowerShell, we had better make the target framework of the project (server and client) above 4.6.2.
https://github.com/dotnet/docs/issues/12000
Feel free to let me know if there is anything I can help with.