-
Notifications
You must be signed in to change notification settings - Fork 561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to prefer TLS 1.1 for BasicHttpsBinding #3442
Comments
Okay, I have discovered a fix and another issue. I was testing with a certificate that supports the latest signature hash algorithm at it appears that
Results in the certificate not being sent. My solution was using Endpoint behaviours. Full code:
I believe that I shouldn't have to use EndpointBehaviours and I should be able to configure WCF via the properties provided by the generated ClientBase objects. If I force Tls11 I am able to use the older certificate. To me, this looks like that somewhere within WCF code it disregards settings provided to it. I'll see if I can manage to build WCF from source and debug the issue. |
There's a lot of questions through this issue so I'll start from the top and at the end will sum up the solution to your problem.
The class Your next issue is why your client certificate isn't getting used. You need to tell WCF that you want to use the certificate. The way you do this is by specifying the client credential type on the binding or tell the binding element that a client certificate is required: var binding = new BasicHttpsBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; or var binding = new BasicHttpsBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; Doing this tells WCF to get the client certificate from the ClientCredentials class and set in on the HttpClientHandler. Exposing HttpClientHandler or the concept of SslProtocols on the client class generated doesn't make a lot of sense. Your binding might not use HTTP or SSL/TLS at all, for example, it could be NetTcpBinding using windows authentication. The purpose of BindingParameterCollection is to enable you to pass extra information to the BindingElement which can't be added in a more abstract way via API's. In theory we could add a property to HttpsTransportBindingElement to control the SslProtocol used, but that wouldn't work on the .NET Framework as the scope of setting which protocol to use is different. The .NET Framework uses HttpWebRequest so we can't expose any HttpWebRequest of HttpClientHandler semantics on the public api surface as it wouldn't make sense on all platforms. The generated class is generated as a partial class so you can extend it by creating your own GeneratedSvcUtilClient.cs file and extend the behavior. E.g. something like this: public class SslProtocolCertificateEndpointBehavior : IEndpointBehavior
{
public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls12;
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
bindingParameters.Add(new Func<HttpClientHandler, HttpMessageHandler>(x =>
{
x.SslProtocols = this.SslProtocols;
return x; // You can just return the modified HttpClientHandler
}));
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
public partial class GeneratedSvcUtilClient
{
public System.Net.SslProtocols SslProtocols
{
get
{
var behavior = Endpoint.EndpointBehaviors.Find<SslProtocolCertificateEndpointBehavior>();
if (behavior != null} return behavior.SslProtocols;
return SslProtocols.Tls12;
}
set
{
var behavior = client.Endpoint.EndpointBehaviors.Find<SslProtocolCertificateEndpointBehavior>();
if (behavior == null)
{
behavior = new SslProtocolCertificateEndpointBehavior();
Endpoint.EndpointBehaviors.Add(behavior);
}
behavior.SslProtocols = value;
}
}
} |
I appreciate the detailed response. I'll try to break my issues up more next time. Embarrassing that I forgot about And I agree, having the generated client class aware of the transport layer doesn't make sense; the truck doesn't care what is being transported and the cargo doesn't care how it gets to where its going (that is how I rationalise it). That is why I would have liked to have the SSLProtocols be defined via the So I wish to provide my own "truck" to the client constructor parameters allow, I derive from In this example,
Its like the client doesn't generate the channel factory from the binding it is given which is what I would expect it would do. Otherwise why have BuildChannelFactory? I am trying to debug the issue using the wcf source code, I can compile it but the structure of the project is beyond my current skill set to deal with. |
I think I see your problem. That method isn't generally called directly on the Binding with most code paths. What usually happens is Binding.CreateBindingElements() is called and passed to CustomBinding which is then used to call BuildChannelFactory. A Binding isn't designed to modify the BuildChannelFactory behavior, it's there to modify the BindingElements returned when calling CreateBindingElement. The call you need to derive from and modify would be HttpsTransportBindingElement and make the changes in the BuildChannelFactory method on that class. |
I did that with |
Figured how to debug with source from WCF. I will find why BuildChannelFactory isn't being invoked soon I hope. |
Thanks for reviewing my issue, I'll rely on the EndpointBehavious instead of the Bindings, I am just "yak shaving" at this point. As far as I can tell the ClientBase instantiates a new ClientChannel rather than building one from the bindings which is confusing, why I am able to override the BuildChannelFactory method if it isn't used? I imagine it is used by internal developers to build the underlying library.
|
Every usage of the virtual method Binding.BuildChannelFactory that I could find was on the CustomBinding class. So basically a new CustomBinding is created from the passed in Binding by calling Binding.CreateBindingElements and passing it to the CustomBinding constructor. Then BuildChannelFactory is called on CustomBinding. The only usage for the BuildChannelFactory method outside of CustomBinding would be if you want to work with raw Message objects and not use contracts. Then you could call |
Thanks, I appreciate the time you have spent. |
Maybe the issue should be titled: Overridden
BindingElement.BuildChannelFactory
not invoked.I have a requirement to consume some SOAP webservices. We have a client certificate signed using MD5 and therefore it is unusable for TLS 1.2.
I understand that
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
is not usable anymore but I am unable to find any alternative. I have read through polymorphic inheritance treechain that isBasicHttpsBinding
to discover that its aBinding
that usesHttpsTransportBindingElement
andHttpTransportBindingElement
. I found the capability to alter theHttpClientFactory
using:wcf/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/HttpChannelFactory.cs
Lines 379 to 383 in 1083786
but I cannot find a way to populate the
BindingContext
that is passed toHttpChannelFactory
with the requiredFunc<>
that is pulled out here:wcf/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/HttpChannelFactory.cs
Line 138 in 1083786
In general it appears that
BuildChannelFactory
is not used and instead a newHttpChannelFactory
is instantiated. If so, what is the point ofBindingElement.BuildChannelFactory
and how do I go about adding my own properties to theBindingContext
andBindingElement
used byHttpChannelFactory
:wcf/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/HttpChannelFactory.cs
Lines 59 to 60 in 1083786
Below is my code from latest attempt. I have tried variations of the below.
The text was updated successfully, but these errors were encountered: