Search code examples
c#asp.net-coresslhttpclient

C# .NET Core 3.1 The SSL connection could not be established


I use an OData service with an C# ASP.NET Core 3.1 service inside a docker container from SAP with a customer self-signed certificate.

In the meantime I have tried a thousand things, but the error persists.

System.InvalidOperationException: An error occurred while processing this request. mdt2oowvsap_1 | ---> System.Data.Services.Client.DataServiceTransportException: The SSL connection could not be established, see inner exception. The remote certificate is invalid according to the validation procedure.

Even the unsafe solutions like using HttpClientHandler.ServerCertificateCustomValidationCallback with direct return true did not change anything.

 public MyService()
 {
        :
        handler = new HttpClientHandler()
        {
            Credentials = new NetworkCredential(Username, Password, Domain),
            PreAuthenticate = true,                
            ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
            {
                if (sslPolicyErrors == SslPolicyErrors.None)
                {
                    logger.LogDebug($"No SSL policy errors!");
                    return true;   //Is valid
                }

                logger.LogDebug($"Get certificate hash: {cert.GetCertHashString()}");
                // From: https://stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors
                if (!String.IsNullOrEmpty(certificateHash) && cert.GetCertHashString().Equals(certificateHash))
                {
                    // Get hash string via: openssl s_client -connect <host>:<port> < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin
                    // see: https://stackoverflow.com/questions/5164804/get-certificate-fingerprint-of-https-server-from-command-line
                    logger.LogDebug($"Using certificate hash: {certificateHash}");
                    return true;
                }
                return false;
            },
            UseCookies = true,
            CookieContainer = cookieContainer
        };
        String[] files = Directory.GetFiles("./certs/", "*.*", SearchOption.TopDirectoryOnly);
        logger.LogInformation($"Found {files.Length} certificate files");
        // see: https://stackoverflow.com/questions/40014047/add-client-certificate-to-net-core-httpclient
        foreach (string cfile in files)
        {
            try
            {
                logger.LogDebug($"Try adding {cfile} as trusted client certificate...");
                handler.ClientCertificates.Add(new X509Certificate2(Path.GetFullPath(cfile)));
            }catch(Exception e)
            {
                logger.LogInformation($"Exception while adding certificate file {cfile} to 'ClientCertificates'");
                logger.LogError(e.ToString());
            }
        }
        httpClient = new HttpClient(handler);
        :
 }

The last attempt was to download the certificate and give it to the HttpClientHandler using ClientCertificates.Add. Without success.

Using curl, passing this certificate file works.

 $> curl --location --request GET 'https://customer.de:1234/sap/opu/odata/something/useful_srv' \
 --header 'Authorization: Basic ABCDEFGHIJKLMNOPQRST='
 curl: (60) SSL certificate problem: self signed certificate
 More details here: https://curl.haxx.se/docs/sslcerts.html
 :
 $> echo -n | openssl s_client -connect customer.de:1234 -servername customer.de | \
 openssl x509 > /full/path/to/customer.cert
 depth=0 CN = customer.de
 verify error:num=18:self signed certificate
 verify return:1
 depth=0 CN = customer.de
 verify return:1
 DONE
 $> 
 $> curl --location --cacert '/full/path/to/customer.cert' --request GET \
 'https://customer.de:1234/sap/opu/odata/something/useful_srv' \
 --header 'Authorization: Basic ABCDEFGHIJKLMNOPQRST='
 <?xml version="1.0" encoding="utf-8"?><app:service xml:lang="de" xml:base="https:blablabla.../></app:service>
 $> _

Does anyone have another idea?

Solutions viewed (incomplete):

Thanks in advance.


Solution

  • The solution to the problem was to make the "self-signed" certificate available to the Docker container or the operating system it contains (Ubuntu) and provide it with

    cp certs/customer.cert /usr/local/share/ca-certificates/customer.crt &&
    update-ca-certificates

    Now the communication works over SSL.