Question

I have some self-hosted WCF services using CustomBinding for HTTP protocol on a specific port. I use BinaryMessageEncodingBindingElement and HttpTransportBindingElement so far without problem.

Now I need to secure a bit more by using HTTPS but with NO cert. I switched to HttpsTransportBindingElement and set RequireClientCertificate to false.

I have no cert installed on that port. I checked by running "netsh http show sslcert".

And I get follow error when I try to add my service to a WPF app (browsing with Chrome I get "This webpage is not available"):


There was an error downloading 'https://localhost:8080/myhost/myservice.svc'.
The underlying connection was closed: An unexpected error occurred on a send.
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
An existing connection was forcibly closed by the remote host
Metadata contains a reference that cannot be resolved: 'https://localhost:8080/myhost/myservice.svc'.
An error occurred while making the HTTP request to 'https://localhost:8080/myhost/myservice.svc'.
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.
The underlying connection was closed: An unexpected error occurred on a send.
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
An existing connection was forcibly closed by the remote host
If the service is defined in the current solution, try building the solution and adding the service reference again.

Here goes my binding:

private System.ServiceModel.Channels.Binding GetHttpBinding(String pName)
    {
        System.ServiceModel.Channels.BindingElementCollection elements = new System.ServiceModel.Channels.BindingElementCollection();

        System.ServiceModel.Channels.BinaryMessageEncodingBindingElement binaryMessageEncoding = new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement();
        binaryMessageEncoding.MessageVersion = System.ServiceModel.Channels.MessageVersion.Default;
        binaryMessageEncoding.ReaderQuotas.MaxArrayLength = this._maxArrayLength;
        binaryMessageEncoding.ReaderQuotas.MaxBytesPerRead = this._maxBytesPerRead;
        binaryMessageEncoding.ReaderQuotas.MaxDepth = this._maxDepth;
        binaryMessageEncoding.ReaderQuotas.MaxNameTableCharCount = this._maxNameTableCharCount;
        binaryMessageEncoding.ReaderQuotas.MaxStringContentLength = this._maxStringContentLength;

        elements.Add(binaryMessageEncoding);

        if (this._applyHttps)
        {
            System.ServiceModel.Channels.HttpsTransportBindingElement transport = new System.ServiceModel.Channels.HttpsTransportBindingElement()
                {
                    MaxBufferSize = this._maxBufferSize,
                    MaxReceivedMessageSize = this._maxReceivedMessageSize,
                    AllowCookies = false,
                    BypassProxyOnLocal = false,
                    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                    MaxBufferPoolSize = this._maxBufferPoolSize,
                    TransferMode = TransferMode.Buffered,
                    UseDefaultWebProxy = true,
                    ProxyAddress = null,
                    RequireClientCertificate = false
                };
            elements.Add(transport);
        }
        else
        {
            System.ServiceModel.Channels.HttpTransportBindingElement transport = new System.ServiceModel.Channels.HttpTransportBindingElement()
                {
                    MaxBufferSize = this._maxBufferSize,
                    MaxReceivedMessageSize = this._maxReceivedMessageSize,
                };
            elements.Add(transport);
        }


        System.ServiceModel.Channels.CustomBinding custB = new System.ServiceModel.Channels.CustomBinding(elements);
        custB.Name = pName;
        custB.SendTimeout = new TimeSpan(0, 2, 0);
        return custB;
}

And I configure the service host with this method:

private void ConfigureBinaryService(ServiceHost pHost, Type pType, String pServiceName)
    {
        pHost.AddServiceEndpoint(pType, this.GetHttpBinding(pType.Name), String.Empty);
        pHost.AddServiceEndpoint(pType, this.GetNetTcpBinding(pType.Name), String.Empty);

        pHost.Description.Endpoints[0].Name = pType.Name + "_BasicBin";
        pHost.Description.Endpoints[1].Name = pType.Name + "_TCP";

        pHost.OpenTimeout = new TimeSpan(0, 2, 0);
        pHost.CloseTimeout = new TimeSpan(0, 2, 0);

        System.ServiceModel.Description.ServiceMetadataBehavior metadataBehavior = pHost.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>();
        if (metadataBehavior == null)
        {
            metadataBehavior = new System.ServiceModel.Description.ServiceMetadataBehavior();
            pHost.Description.Behaviors.Add(metadataBehavior);
        }
        if (this._applyHttps)
            metadataBehavior.HttpsGetEnabled = true;
        else
            metadataBehavior.HttpGetEnabled = true;

        metadataBehavior.MetadataExporter.PolicyVersion = System.ServiceModel.Description.PolicyVersion.Policy15;

        if (this._applyHttps)
            pHost.AddServiceEndpoint(System.ServiceModel.Description.ServiceMetadataBehavior.MexContractName
                , System.ServiceModel.Description.MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
        else
            pHost.AddServiceEndpoint(System.ServiceModel.Description.ServiceMetadataBehavior.MexContractName
                , System.ServiceModel.Description.MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

        pHost.AddServiceEndpoint(System.ServiceModel.Description.ServiceMetadataBehavior.MexContractName
            , System.ServiceModel.Description.MetadataExchangeBindings.CreateMexTcpBinding(), this._NetTcpComm + @"/" + pServiceName + @"/mex");

        pHost.Description.Endpoints[2].Name = pType.Name + "_mex_BasicBin";
        pHost.Description.Endpoints[3].Name = pType.Name + "_mex_TCP";

        foreach (var item in pHost.Description.Endpoints[0].Contract.Operations)
            item.Behaviors.Find<System.ServiceModel.Description.DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = System.Int32.MaxValue;

        foreach (var item in pHost.Description.Endpoints[1].Contract.Operations)
            item.Behaviors.Find<System.ServiceModel.Description.DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = System.Int32.MaxValue;


        System.ServiceModel.Description.ServiceDebugBehavior debugBehavior =
            pHost.Description.Behaviors.Find<System.ServiceModel.Description.ServiceDebugBehavior>();
        if (debugBehavior == null)
        {
            debugBehavior = new System.ServiceModel.Description.ServiceDebugBehavior();
            pHost.Description.Behaviors.Add(debugBehavior);
        }
        debugBehavior.IncludeExceptionDetailInFaults = true;
    }

When this._applyHttps is false, my service is accessible both by browser and reference in WPF project.

So I ask for help for the first time after enjoying for so long all your help without asking directly. What am I missing? As it's not hosted under IIS should I still need a cert to install on the server side only for the specific port?

Thanks guys in advance! And if someone has already answered this case I'm sorry for not finding it...

Was it helpful?

Solution

So like I had guessed I just needed to create a self-signed cert for the server side only and bind it to the port with netsh command. No cert needed on client side meaning a quasi HTTPS WITHOUT CERT.

Note: I had it work on my computer. I will try to update this post once deployed in real environment and if I had to address any mistake.

And I know at some point we will go full cert on client side. One stone at a time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top