0

I have a selfhosted WCF service publishing a REST web API. The service is configured programmatically, and currently is correctly working via HTTP. Now I need to make it work over HTTPS, with an authentication based on certificate file. I know the suggested way to do this is installing the certificate in the Windows Certificate Store on the server machine, but this way is not possible in my circumstances. I need to load the certificate from the file.

After some resarches, I wrote my code, but when I try accessing the web service, a System.ServiceModel.CommunicationException is thrown, with the message: An error occurred while making the HTTP request to ... This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.

Here's my code for the server side:

_host = new WebServiceHost(_hostedService, Uri);

//Configuring the webHttpBinding settings
var httpBinding = new WebHttpBinding();
httpBinding.Security.Mode = WebHttpSecurityMode.Transport;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
httpBinding.SendTimeout = new TimeSpan(0, 5, 0);
httpBinding.MaxBufferSize = 2147483647;
httpBinding.MaxBufferPoolSize = 2147483647;
httpBinding.MaxReceivedMessageSize = 2147483647;
httpBinding.ReaderQuotas.MaxDepth = 2147483647;
httpBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
httpBinding.ReaderQuotas.MaxArrayLength = 2147483647;
httpBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
httpBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;

//Add the endpoint with the webHttpBinding settings to the WebServiceHost configuration
_host.AddServiceEndpoint(typeof(IService), httpBinding, Uri);

ServiceDebugBehavior stp = _host.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
ServiceBehaviorAttribute sba = _host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
sba.InstanceContextMode = InstanceContextMode.Single;
ServiceMetadataBehavior smb = new ServiceMetadataBehavior() { HttpsGetEnabled = true };
_host.Description.Behaviors.Add(smb);

X509Certificate2 trustedCertificate = new X509Certificate2("certificate.pfx", "password");
_host.Credentials.ServiceCertificate.Certificate = trustedCertificate;
_host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

Here's my code for the client side:

var httpBinding = new WebHttpBinding();
httpBinding.Security.Mode = WebHttpSecurityMode.Transport;
httpBinding.Security.Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Certificate };
var httpUri = new Uri(String.Format("https://{0}:{1}", ipAddress, tcpPort));
var httpEndpoint = new EndpointAddress(httpUri);
var newFactory = new ChannelFactory<IService>(httpBinding, httpEndpoint);
newFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());

X509Certificate2 trustedCertificate = new X509Certificate2("certificate.pfx", "password"); //SSL
newFactory.Credentials.ClientCertificate.Certificate = trustedCertificate;

var channel = newFactory.CreateChannel();

var response = channel.Ping("helo");

The Exception is thrown on the last line (channel.Ping("helo")).

I need to make it work WITHOUT installing the certificate on the server machine.

Thank you very much.

Bye.

1 Answers1

2

As far as I know, when we host the self-hosted WCF service over Https, whatever way we use (load certificate file or configure the certificate via Windows Certificate Store), it is impossible to make the service works normally. The only way we need to do is binding the certificate manually by using the following command.

netsh http add sslcert ipport=0.0.0.0:8000 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF}

Here is official document, wish it is useful to you.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate

https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
Here are some examples were ever written by me.
WCF Service over HTTPS without IIS, with SSL Certificate from CERT and KEY strings or files

Chrome (v71) ERR_CONNECTION_RESET on Self Signed localhost on Windows 8 Embedded
Feel free to let know if there is anything I can help with.

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • This is what I was afraid of... Thank you very much. – MonsterMash Mar 06 '19 at 08:39
  • Just another question: how can I know the certhash of my certificate.pfx file? – MonsterMash Mar 06 '19 at 08:50
  • Certhash parameter is the thumbprint of the certificate, you could get it by programatically, or certificate property(Install, and check it in Windows Certificate Store). X509Certificate2 cert = new X509Certificate2("1.pfx", "123456"); Console.WriteLine(cert.Thumbprint); – Abraham Qian Mar 06 '19 at 08:58
  • By the way, the method you provided is used to protect communication over http, for example, if we want to set up custom username/password authentication, we need to use the above methods to provide a certificate to implement the function. Besides, if we host the service over https in IIS, the IIS binding could help us to binding the certificate. https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl – Abraham Qian Mar 06 '19 at 09:07
  • netsh http add sslcert ipport=0.0.0.0:8000 certhash=... appid={...} seems to work only if the certificate is into the Certificate Store... otherwise I have the error 1312... It seems nothing of my needs are achievable... :( – MonsterMash Mar 06 '19 at 13:43
  • I think you should consider the reasonableness of your need. If possible, please mark it useful so that the others encountered the problem are willing to read this reply. thanks. – Abraham Qian Mar 07 '19 at 06:26