-
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
Could not establish trust relationship for the SSL/TLS secure channel with authority #2499
Comments
Will this work: BasicHttpsBinding binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
endpointAddress = new EndpointAddress(new Uri("http://myserver/MyService.svc"));
factory = new ChannelFactory<IService>(binding, endpointAddress);
factory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication();
factory.Credentials.ServiceCertificate.SslCertificateAuthentication.CertificateValidationMode = X509CertificateValidationMode.None; |
Thanks a lot @mconnew |
Hello, I have same problem, but solution from @mconnew doesn't work for me. var client = new PartnerApiClient { ClientCredentials = { UserName = { UserName = "testapi", Password = "dfdfTT7" } } };
client.ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
client.ChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
await client.GetTariffPlanListAsync() // Could not establish trust relationship for the SSL/TLS secure channel with authority 11.22.33.44:5555 A #region Assembly System.ServiceModel.Primitives, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Users\Artem\.nuget\packages\system.servicemodel.primitives\4.4.1\ref\netstandard2.0\System.ServiceModel.Primitives.dll
#endregion In classic .net 4.7 this code works fine with System.Net.ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; |
Hello, it seems that I encounter the same problem calling a SOAP service with self certificate from an asp.net core 2.1 webapi running in .net core 2.1: In my case, the fix given by @mconnew work with version 4.4.2 of System.ServiceModel.Primitives and System.ServiceModel.Http but fail with version 4.5.0 (just changing nuget package version no code modification). |
@Etrimus, you are using ChannelFactory.Credentials.ServiceCertificate.Authentication and my example is using ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication. Change your code to match my example and it should work for you, @gcelet, we have extensive tests around this area so if something broke in our code, we would see it in our test results. I don't suppose you are running on OSX? |
@mconnew No our project is developped on Windows and run in Docker on linux in production. |
I still get the problem with version 4.5.1 of System.ServiceModel.Primitives and System.ServiceModel.Http.
[Test]
public async Task Should_Not_Throw_On_No_Trust_Domain()
{
BasicHttpBinding binding = new BasicHttpBinding
{
CloseTimeout = TimeSpan.Parse("00:10:00"),
OpenTimeout = TimeSpan.Parse("00:10:00"),
ReceiveTimeout = TimeSpan.Parse("00:10:00"),
SendTimeout = TimeSpan.Parse("00:10:00"),
MaxBufferPoolSize = 90000000,
MaxBufferSize = 90000000,
MaxReceivedMessageSize = 90000000,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxDepth = 32,
MaxArrayLength = 90000000,
MaxStringContentLength = 90000000
},
};
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport = new HttpTransportSecurity
{
ClientCredentialType = HttpClientCredentialType.None,
ProxyCredentialType = HttpProxyCredentialType.Basic
};
EndpointAddress remoteAddress = new EndpointAddress("https://mydomain.with.no.trust.com/Service.scv");
ServiceWCF client = new ServiceWCF(binding, remoteAddress);
client.ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication =
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine
};
ServiceResultat serviceResultat;
try
{
ServiceResultat =
await client.callService().ConfigureAwait(false);
client.Close();
}
catch (CommunicationException)
{
client.Abort();
throw;
}
catch (TimeoutException)
{
client.Abort();
throw;
}
catch (Exception)
{
client.Abort();
throw;
}
Assert.IsNotNull(serviceResultat);
}
|
Same issue here, I had to downgrade to 4.4.2 in order to disable the validation. |
Thank you so much man! This is work fine for me :) |
Thanks. This work for me. |
The only difference that I can see if using BasicHttpsBinding instead of BasicHttpBinding. Can you verify if using BasicHttpBinding instead is broken? I think this works on .NET Framework but WCF has so many knobs and options I could be wrong. |
Hi, I changed my unit test above from BasicHttpBinding to BasicHttpsBinding:
These tests runned on .NET Core using sdk 2.1.700. |
Re-opening issue. AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); Also, what OS are you using? |
Hi, Sorry for my late response: i was busy at work. I can confirm that my unit test pass with 4.5.3 configured to not use SocketsHttpHandler: without it it still failed. I run this test on .net core 2.1 with sdk 2.1.701 on windows 10 pro 1809. Hope this helps |
@gcelet This looks like a bug in CoreFx, in order for us to open an issue in their repo we need a little more data from you if possible.
Could you get us that? |
Hi, I worked yesterday on repro but it's seems difficult. I can't post the certificate publicly on github. How can i send you this information privately ? The certificate looks like this: $ openssl x509 -in certificate.crt -text -noout
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 0 (0x0)
Signature Algorithm: md5WithRSAEncryption
Issuer: CN = *.subdomain.wcfbug2499.local
Validity
Not Before: Jun 22 10:23:42 2009 GMT
Not After : Jun 20 10:23:42 2019 GMT
Subject: CN = *.subdomain.wcfbug2499.local
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (1024 bit)
Modulus:
00:b7:f9:b4:6d:9d:13:01:a2:5a:f8:64:c2:9d:49:
f0:40:d6:55:a3:28:4c:3b:70:9d:64:fb:87:5a:1e:
51:5a:e6:08:eb:dd:91:aa:a2:94:50:bf:e3:6b:be:
d9:bf:75:8f:ce:9a:1f:d5:de:6b:20:60:58:74:29:
bd:56:76:b2:cf:bf:34:2b:22:ab:5e:46:78:74:0f:
22:d3:0c:a8:02:c0:c0:d2:84:bb:1f:68:5a:69:23:
f7:3b:73:d0:c3:9b:2c:9b:cd:21:f3:24:2c:d0:7f:
05:11:38:48:9f:77:18:0d:06:5d:70:7c:6d:85:b9:
3e:8d:81:5d:9b:8d:1a:1d:a5
Exponent: 65537 (0x10001)
Signature Algorithm: md5WithRSAEncryption
4c:12:f8:50:ec:ec:36:f4:fb:45:f3:53:19:7a:ad:49:63:c6:
e2:09:d0:41:ec:71:74:b0:88:a2:39:51:4c:8a:8a:4d:2f:5f:
49:d2:4c:ed:23:a8:05:e6:e3:45:6b:a4:da:5e:75:9f:95:74:
82:65:55:09:fb:30:9b:b6:7b:c0:70:79:53:1b:17:5f:d4:8e:
db:dc:15:0e:70:52:35:88:3d:9c:e5:bb:80:b9:16:22:5e:9e:
2f:9a:e0:c6:3c:ea:e5:9b:7e:c7:de:66:fd:a9:fb:25:f3:b1:
70:d5:fb:b9:14:6b:16:0e:29:7a:7c:b8:bd:ce:fc:dd:d9:fa:
98:2b This is not the real certificate: it's was made up and it's likely not working but may be it will help. This certificate expired in june 2019 but the problem happened before the expiration. And it's working as expected when not using SocketsHttpHandler. This is the unit test i use to show the problem: [Test]
public void Should_Not_Throw_On_No_Trust_Domain()
{
//AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
BasicHttpBinding binding = new BasicHttpBinding
{
CloseTimeout = TimeSpan.Parse("00:10:00"),
OpenTimeout = TimeSpan.Parse("00:10:00"),
ReceiveTimeout = TimeSpan.Parse("00:10:00"),
SendTimeout = TimeSpan.Parse("00:10:00"),
MaxBufferPoolSize = 90000000,
MaxBufferSize = 90000000,
MaxReceivedMessageSize = 90000000,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxDepth = 32,
MaxArrayLength = 90000000,
MaxStringContentLength = 90000000
},
};
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport = new HttpTransportSecurity
{
ClientCredentialType = HttpClientCredentialType.None,
ProxyCredentialType = HttpProxyCredentialType.Basic
};
EndpointAddress remoteAddress = new EndpointAddress("https://abc.subdomain.wcfbug2499.local/path-to-service");
WcfServiceClient client = new WcfServiceClient(binding, remoteAddress);
client.ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication =
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine
};
try
{
string serviceResultat = client.DemoClient();
((ICommunicationObject) client).Close();
Assert.IsNotNull(serviceResultat);
}
catch (CommunicationException)
{
client.Abort();
throw;
}
catch (TimeoutException)
{
client.Abort();
throw;
}
catch (Exception)
{
client.Abort();
throw;
}
}
[ServiceContract]
public interface IWcfService
{
[OperationContract]
string DemoClient();
}
public class WcfServiceClient : System.ServiceModel.ClientBase<IWcfService>, IWcfService
{
public WcfServiceClient()
{
}
public WcfServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public WcfServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfServiceClient(string endpointConfigurationName,
System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfServiceClient(System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
/// <inheritdoc />
public string DemoClient()
{
return base.Channel.DemoClient();
}
} It's worked when the switch System.Net.Http.UseSocketsHttpHandler have the value false. It's produced the following stack strace when the switch System.Net.Http.UseSocketsHttpHandler have the value true:
|
Sorry for the slow response, I was on vacation then out sick. There's one more bit of information which I think would be really useful. There's 4 exceptions nesting each other. On the very inner exception, the Win32Exception, can you tell me what the values are of the NativeErrorCode, ErrorCode and HResult properties. They are likely the same, but it's possible they have different values. You can send the public cert of the server to me at my username at microsoft.com. Please make sure you only send me the public part of the certificate and not the private key. |
Hi, Details of Win32Exception are:
Hope this helps but these codes seems really generic ones. I will send you the public certificate later today (i'm in France). |
Error code -2146893048 corresponds to SEC_E_INVALID_TOKEN which has the description "The token supplied to the function is invalid" which I think is what the french in your call stack translates to anyway. I've received your email and I have an answer for you. The server certificate is using really old standards. The signature hash algorithm is md5 which can't be used with the TLS1.2 protocol. The only reason things are working on .NET Framework is the supported SSL protocols doesn't include TLS1.2. This is probably because your application is targeting an older version of the .NET Framework, or you are running on Windows 7. In order to connect to that web service, you will need to downgrade the highest TLS version being used to TLS1.1. WCF doesn't expose an api for doing this directly, but we do have the ability for you to provide a delegate to modify the HttpClientHandler instance that we use. This requires adding a behavior to your channel factory. A full example of a behavior which does what you need can be found in my comment on this issue. |
Oh, and there's another issue you are likely to run into. There's a bug where we don't apply the ProxyCredentialType value to the underlying HttpsTransportBindingElement. It's been fixed and will be in a future release. Details can be found in issue #3551 along with the clunky workaround that someone provided. |
@mconnew Thanks for your quick response. I'm not sure to understand your answer. I don't use .NET Framework in this test: it runs on .NET Core 2.1.12 (only LTS version of .NET Core). I develop on Windows 10 Pro 1809 and run this code in production inside kubernetes on linux. If i upgrade Nuget packages System.ServiceModel.Primitives and System.ServiceModel.Http to version 4.5.3, this test fail. This test passed when using version 4.4.2 of Nuget packages System.ServiceModel.Primitives and System.ServiceModel.Http. I understand that this certificate is using old security standards but i need to be able to call it. It seems that i cannot bypassed the certificate check anymore. The only way i found is to stay on version 4.4.2 of nuget packages System.ServiceModel.Primitives and System.ServiceModel.Http. I tried the other workarounds in this thread but none of them work except disabling "System.Net.Http.UseSocketsHttpHandler" using the context flag. |
Sorry, I got confused by the history as someone else opened the issue originally and their code ran fine on .NET Framework. You can disregard that. Up until WCF 4.4.2, we explicitly instantiated an instance of the Curl based HTTP handler as the generic HttpClientHandler didn't expose sufficient properties for everything we needed to set. From 4.5, we instantiate HttpClientHandler instance as they have now added sufficient API's to HttpClientHandler. This means when using 4.4.2, you end up using the Linux platform specific libcurl based HTTP handler but when using 4.5, you use whatever HttpClientHandler is configured to use, which defaults to SocketsHttpHandler. The app setting reverts the behavior of HttpClientHandler to use the platform specific version which for Linux is based on libcurl. Curl is going to have different behavior around which versions of TLS to support. SocketsHttpHandler supports TLS1.2 by default. Curl must be negotiating a lower version of TLS than SocketsHttpHandler which is why everything is working. In the comment I linked to, there is a behavior you can add to ChannelFactory which allows configuring the HttpClientHandler that WCF instantiates (which is wrapping SocketsHttpHandler) so you can tell it to only use SslProtocols.Tls11. The old certificate is incompatible with TLS 1.2 which is why the request is failing. The Curl based handler (as is always used by WCF in 4.4.2) must be using a version of TLS <= 1.1. The behavior has been written to specifically configure SslProtocols so you can just set a property on the behavior itself. |
Hi, Sorry for my late response: i just returned from vacation. Thank you for response: it explained clearly the problem. I can confirm that using your endpoint behavior SslProtocolCertificateEndpointBehavior to force SslProtocols.Tls11 it worked as expected. Thanks for your help on this issue. For posterity sake, here the complete unit test: public class WcfBug2499UsingLocalDomainTests
{
[Test]
public void Should_Not_Throw_On_No_Trust_Domain()
{
//AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
BasicHttpBinding binding = new BasicHttpBinding
{
CloseTimeout = TimeSpan.Parse("00:10:00"),
OpenTimeout = TimeSpan.Parse("00:10:00"),
ReceiveTimeout = TimeSpan.Parse("00:10:00"),
SendTimeout = TimeSpan.Parse("00:10:00"),
MaxBufferPoolSize = 90000000,
MaxBufferSize = 90000000,
MaxReceivedMessageSize = 90000000,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxDepth = 32,
MaxArrayLength = 90000000,
MaxStringContentLength = 90000000
},
};
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport = new HttpTransportSecurity
{
ClientCredentialType = HttpClientCredentialType.None,
ProxyCredentialType = HttpProxyCredentialType.Basic
};
EndpointAddress remoteAddress = new EndpointAddress("https://abc.subdomain.wcfbug2499.local");
WcfServiceClient client = new WcfServiceClient(binding, remoteAddress)
{
SslProtocols = SslProtocols.Tls11
};
client.ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication =
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine
};
try
{
string serviceResultat = client.DemoClient();
((ICommunicationObject) client).Close();
Assert.IsNotNull(serviceResultat);
}
catch (CommunicationException communicationException)
{
client.Abort();
throw;
}
catch (TimeoutException timeoutException)
{
client.Abort();
throw;
}
catch (Exception exception)
{
client.Abort();
throw;
}
}
}
[ServiceContract]
public interface IWcfService
{
[OperationContract]
string DemoClient();
}
public class WcfServiceClient : System.ServiceModel.ClientBase<IWcfService>, IWcfService
{
public WcfServiceClient()
{
}
public WcfServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public WcfServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfServiceClient(string endpointConfigurationName,
System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public WcfServiceClient(System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public SslProtocols SslProtocols
{
get
{
var behavior = Endpoint.EndpointBehaviors.OfType<SslProtocolCertificateEndpointBehavior>().FirstOrDefault();
if (behavior != null)
{
return behavior.SslProtocols;
}
return SslProtocols.Tls12;
}
set
{
var behavior = Endpoint.EndpointBehaviors.OfType<SslProtocolCertificateEndpointBehavior>().FirstOrDefault();
if (behavior == null)
{
behavior = new SslProtocolCertificateEndpointBehavior();
Endpoint.EndpointBehaviors.Add(behavior);
}
behavior.SslProtocols = value;
}
}
/// <inheritdoc />
public string DemoClient()
{
return base.Channel.DemoClient();
}
}
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 = 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)
{
}
} |
@gcelet Glad it worked for you! |
I'm trying to use a digital certificate already installed in my PC.
I'm using ASPNET CORE 2.0, Framework 4.7 and VS 2017 15.5.3
This only occurs because the certificate is not valid: NET::ERR_CERT_AUTHORITY_INVALID
In my winform application, this works using this:
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
The text was updated successfully, but these errors were encountered: