Gideon
Gideon

Reputation: 1068

The SSL connection could not be established. The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

I am trying to submit a request to a web API. I am coding a web API with Azure App Services using C#. This code does the request:

    _objClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", credential);
    var multipartFormContent = new MultipartFormDataContent();
    multipartFormContent.Add(new StringContent(product.Name), name: "name");
    multipartFormContent.Add(new StringContent(product.Price), name: "price");
    MemoryStream ms = new(product.catalogue);
    var fileStreamContent = new StreamContent(ms);
    fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    multipartFormContent.Add(fileStreamContent, name: "content", fileName: product.Name);
    var response = _objClient.PostAsync(_settings.UploadProductCatalogueUrl, multipartFormContent).GetAwaiter().GetResult();

Invoking the PostAsync method returns this error:

Exception message: The SSL connection could not be established, see inner exception.

Inner exception: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot.

Stack trace: at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)\r\n at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)\r\n at ProductCatalogue.UploadProductCatalogue(CatalogueDto catalogue)

It does work when running it locally, this only fails when deployed to Azure.

Upvotes: 0

Views: 1890

Answers (1)

Gideon
Gideon

Reputation: 1068

What worked for me was to invoke the ConfigurePrimaryHttpMessageHandler for the HttpClient, and overload the ServerCertificateCustomValidationCallback method, to return true:

    private static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddHttpClient("ProductCatalogueClient",
            client =>
            {
                client.BaseAddress = new Uri(builder.Configuration["Settings:productCatalogueUrl"]);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
            }
        )
        .ConfigurePrimaryHttpMessageHandler(configure =>
            new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
                {
                    return true;
                }
            });

Be aware this bypasses the certificate validation, in our case this was OK, but it might generate a security issue in your case.

Upvotes: 0

Related Questions