Exception: System.ServiceModel.Security.SecurityNegotiationException: Failed to establish a secure channel for SSL/TLS with the authority

392 views Asked by At

I am trying to connect to a WCF service with c# (SOAP Service). I am using a SLL/TLS version 1.2 certificate. The certificate has the extension .p12. The certificate is correct as when I make the request in the web browser everything flows correctly. It is also installed in MMC. The problem is in the client, which makes the connection but at the last moment the connection is closed, skipping the exception in the title. I have observed the traffic with Wireshark and both the connection to the server and the decryption of the key are done correctly. Could someone help me with this error? I leave you the code and the content of the App.config and the output of the error together with the one of the stack. Thanks in advance

PD: Using RestSharp, it connects the client perfectly, and I get all the xml from the query, but it is more tedious. Because I have to be sending headers, bodies, etc.. for each query. With WCF is more comfortable and I would like to use it.

static void Main(string[] args)
        {
            // Set TLS version 1.2
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;            

            // Certificate file path and password            
            string certFilePath = @"MyPath\MyCertificate.p12";
            SecureString certPassword = GetSecureString("MyPassword");

            // Upload the certificate from the file
            X509Certificate2 cert = new X509Certificate2(
                certFilePath, 
                certPassword, 
                X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);

            Console.WriteLine(cert);

            // Deciphering the key 
            try
            {
                RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
                rsa.PersistKeyInCsp = false;
                RSAParameters rsaParams = rsa.ExportParameters(true);

                // Obtain the SHA-256 summary of the certificate
                SHA256Managed sha256 = new SHA256Managed();
                byte[] certHash = sha256.ComputeHash(cert.RawData);
                string certHashString = Convert.ToBase64String(certHash);

                Console.WriteLine("Private key successfully decrypted.");
                Console.WriteLine("SHA-256 summary of the certificate: " + certHashString);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error decrypting the private key: " + ex.ToString());
            }

            Console.ReadLine();

            // We make the inquiry through WCF
            try
            {
                // Create a WCF client instance                
                QueryServiceClient clienteQuery = new QueryServiceClient();
              
                // Configuring the certificate in the WCF client
                //clienteQuery.ClientCredentials.ClientCertificate.Certificate = cert;
                
                clienteQuery.ClientCredentials.ClientCertificate.SetCertificate(
                    StoreLocation.CurrentUser,
                    StoreName.My,
                    X509FindType.FindByThumbprint,
                    cert.Thumbprint
                );

                // Using WCF client methods                         
                var accessProfiles = clienteQuery.getAccessProfiles();
                foreach (var profile in accessProfiles)
                {
                    Console.WriteLine("Access profile: " + profile);
                }
                Console.ReadLine();

                // Close the client after use
                //clienteQuery.Close();
                
            }
            catch (Exception ex)
            {
                // Handle any exception
                Console.WriteLine("Exception: " + ex.ToString());
                Console.ReadLine();
            }
        }

        // Method for SecureString
        private static SecureString GetSecureString(string password)
        {
            SecureString secureString = new SecureString();
            foreach (char c in password)
            {
                secureString.AppendChar(c);
            }
            return secureString;
        }
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03fkg89kg890a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="WorkServicePortBinding">
          <security mode="Transport" />
        </binding>
        <binding name="WorkServicePortBinding1" />
        <binding name="QueryServicePortBinding">
          <security mode="Transport" />
        </binding>
        <binding name="QueryServicePortBinding1" />
        <binding name="ImportServicePortBinding">
          <security mode="Transport" />
        </binding>
        <binding name="ImportServicePortBinding1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://mywebAPI.com:8989/work/v2/"
        binding="basicHttpBinding" bindingConfiguration="WorkServicePortBinding"
        contract="WorkServices.WorkService" name="WorkServicePort" />
      <endpoint address="https://mywebAPI.com:8989/query/v2/"
        binding="basicHttpBinding" bindingConfiguration="QueryServicePortBinding"
        contract="QueryServices.QueryService" name="QueryServicePort" />
      <endpoint address="https://mywebAPI.com:8989/import/v2/"
        binding="basicHttpBinding" bindingConfiguration="ImportServicePortBinding"
        contract="ImportServices.ImportService" name="ImportServicePort" />
    </client>
  </system.serviceModel>
</configuration>
Exception: System.ServiceModel.Security.SecurityNegotiationException: Failed to establish a secure channel for SSL/TLS with the authority. 'mywebAPI.com:8989'. ---> System.Net.WebException: Anulada la solicitud: No se puede crear un canal seguro SSL/TLS.
   en System.Net.HttpWebRequest.GetResponse()
   en System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of internal exception stack tracking ---

Server stack trace:
   en System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
   en System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   en System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   en System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   en System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   en System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   en System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

I was trying to query a service to receive data. I did what I show in the code but the connection closes without fetching the data.

2

There are 2 answers

1
QI You On

I think the reason might be that the client can't find the corresponding certificate. You can try adding the following to your configuration file:

<endpointBehaviors>
      <behavior name="Service1Nehavior">
        <clientCredentials>
          <clientCertificate findValue="QiYouTest" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="TrustedPeople" />
        </clientCredentials>
      </behavior>
    </endpointBehaviors>

findValue:Certificate name

x509FindType:Type

StoreLocation:Storage location

Storename:Storage Name

0
QI You On

Is it possible to modify the configuration on the code side. Try:

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;