alexrainman / ModernHttpClient

ModernHttpClient
MIT License
126 stars 28 forks source link

Certificate pinning failure: chain error #68

Closed simonc9999 closed 4 years ago

simonc9999 commented 4 years ago

Android has suddenly started throwing this error "Certificate pinning failure: chain error at ModernHttpClient.Native.MessageHandler.SendAsync". The code is attempting to connect an SSL rest api site. This used to work but suddenly stopped working. Any idea if there has been some sort of security update to Android which has broken things? This is the code I'm using to try to connect and execute a POST. Same code is working fine on an iOS device.

    private HttpClient CreateJsonHttpClient(string authToken)
    {
        var handler = new NativeMessageHandler();
        handler.Timeout = HttpTimeout;
        handler.AutomaticDecompression = DecompressionMethods.GZip;
        var httpClient = new HttpClient(handler);
        httpClient.Timeout = HttpTimeout;
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        if (!string.IsNullOrEmpty(authToken))
        {
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
        }
        return httpClient;
    }

           public async Task<T> PostAsync<T>(string uri, T data, string authToken = "")
    {
        try
        {
            using (HttpClient httpClient = CreateJsonHttpClient(authToken))
            {

                var content = new StringContent(JsonConvert.SerializeObject(data));
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                string jsonResult = string.Empty;

                var responseMessage = await Policy
                    .Handle<WebException>(ex =>
                    {
                        Debug.WriteLine($"{ex.GetType().Name + " : " + ex.Message}");
                        return true;
                    })
                    .WaitAndRetryAsync
                    (
                        5,
                        retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
                    )
                    .ExecuteAsync(async () => await httpClient.PostAsync(uri, content));

                if (responseMessage.IsSuccessStatusCode)
                {
                    jsonResult = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
                    var json = JsonConvert.DeserializeObject<T>(jsonResult);
                    return json;
                }

                if (responseMessage.StatusCode == HttpStatusCode.Forbidden ||
                    responseMessage.StatusCode == HttpStatusCode.Unauthorized)
                {
                    throw new ServiceAuthenticationException(jsonResult);
                }

                throw new HttpRequestExceptionEx(responseMessage.StatusCode, jsonResult);
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine($"{ e.GetType().Name + " : " + e.Message}");
            throw;
        }
    }
cravecode commented 4 years ago

Same issue here! Thanks for reporting @simonc9999

cravecode commented 4 years ago

@simonc9999, it turned out the issue for me was caused by a certificate in our SSL signing chain had expired. A common cert by Sectigo (AKA COMODO) in their signing chain expired in May of 2020. Most browsers and devices weren't negatively effected because the new cert was already commonly distributed, but not all. We reissued a new certificate for our API endpoints signed by DigiCert, this fixed our issue.

Check your SSL/TLS certificate with SSL Labs and look for any expired certs in the signing chain.

Reference: https://sectigo.com/resource-library/sectigos-addtrust-root-is-soon-to-expire-what-you-need-to-know

simonc9999 commented 4 years ago

@cravecode thanks that explains why it suddenly stopped working on June 1. We have a sectigo cert and the root cert expired May 31.

alexrainman commented 4 years ago

Let me try to improve the error message so this kind of issues is easier to identify.