How to ignore Self Signed Certificate errors in Windows Store apps (8.1)


There are some very limited times you need to ignore Server Certificate errors.  In fact the dangers of doing this are published here: The most dangerous code in the world: validating SSL certificates in non-browser software.  Up until Windows 8.1 you could not do this in Windows Store apps with our HTTP classes.  Now you can do this in .NET, C++ and JavaScript Windows Store apps!

If and ONLY if you must do this, the capability to ignore Server Certificate errors has been enabled in the  Windows.Web.Http namespace.  This new namespace allows you to do a lot of things with HTTP requests that previously were not possible.

UPDATE:  See the accompanying video: https://channel9.msdn.com/Series/Windows-Store-Developer-Solutions/How-to-ignore-Self-Signed-Certificate-errors-in-Windows-Store-apps-81

Scenario

I have an endpoint internal to my network and the certificate is a self signed certificate.  For some reason I cannot deploy the certificate to all the necessary clients and install them as a trusted root.

Solution

HttpClient allows me to create an HttpBaseProtocolFeature that exposes a list that I can add Certificate errors I wish to ignore.  Using this filter I can ignore particular errors.  In my case I want to ignore errors from a certain certificate authority so my code allows me to specify that too (I default to using the URI Host for testing).  The code is well commented and should be easy to follow (Note: This functionality is NOT available using the System.Net.Http.HttpClient class):

Code

Copy Code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Security.Cryptography.Certificates;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Web.Http; // This makes it all possible!  Not System.Net
using Windows.Web.Http.Filters;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace App4
{

    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        // HttpClient used for (almost) all calls in my application
        HttpClient appHttpClient;
                
        public MainPage()
        {
            this.InitializeComponent();
            // create an HttpClient for web calls in this app
            appHttpClient = new HttpClient();
        }


        // Test request that will fix up expected cert errors in this case
        private async Task<string> testCert(Uri theUri, string theExpectedIssuer)
        {
            // Simple GET for URI passed in
            HttpRequestMessage aReq = new HttpRequestMessage(HttpMethod.Get, theUri);
            // Retry for cert error issues?
            bool retryIgnoreCertErrors = false;
            // return value
            string retVal = "trying to GET";
            // Base  filter that I may use later 
            HttpBaseProtocolFilter aHBPF = null;

            try
            {
                HttpResponseMessage aResp = await appHttpClient.SendRequestAsync(aReq);
                // hit here if no exceptions!
                retVal = "No Cert errors";
             }
            catch (Exception  ex)
            {
                retVal = ex.Message;

                // Mask the HResult and if this is error code 12045 which means there was a certificate error
                if ((ex.HResult & 65535) == 12045)
                {
                    // Get a list of the server cert errors
                    IReadOnlyList<ChainValidationResult> errors = aReq.TransportInformation.ServerCertificateErrors;

                    // I expect that the cert is expired and it is untrusted for my schenario...
                    if ((errors !=null) && (errors.Contains(ChainValidationResult.Expired) 
&& errors.Contains(
ChainValidationResult.Untrusted))) { // Specifically validate that this came from a particular Issuer if (aReq.TransportInformation.ServerCertificate.Issuer == theExpectedIssuer) { // Create a Base Protocol Filter to add certificate errors I want to ignore... aHBPF = new HttpBaseProtocolFilter(); // I purposefully have an expired cert to show setting multiple Ignorable Errors aHBPF.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); // Untrused because this is a self signed cert that is not installed aHBPF.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); // OK to retry since I expected these errors from this host! retryIgnoreCertErrors = true; } } } } try { // Retry with a temporary HttpClient and ignore some very specific errors! if (retryIgnoreCertErrors) { // Create a Client to use just for this request and ignore some cert errors. HttpClient aTempClient = new HttpClient(aHBPF); // Try to execute the request (should not fail now for those two errors) HttpRequestMessage aTempReq = new HttpRequestMessage(HttpMethod.Get, theUri); HttpResponseMessage aResp2 = await aTempClient.SendRequestAsync(aTempReq); retVal = "No Cert errors"; } } catch (Exception ex2) { // some other exception occurred retVal = ex2.Message; } return retVal; } private async void Button_Click(object sender, RoutedEventArgs e) { Uri targetUri = new Uri(txtInputUrl.Text); txtResult.Text = await testCert(targetUri, targetUri.Host); } } }

Conclusion

You should ONLY use this technique for very well defined scenarios that there is absolutely no way around.  You are responsible to ensure that the target you are hitting is indeed the correct endpoint because by ignoring the Certificate Errors you are abandoning the security the Server Certificates provide!

Follow us at @WSDevSol!

More Information

The most dangerous code in the world: validating SSL certificates in non-browser software.

HttpClient

HttpBaseProtocolFilter


Comments (5)

  1. Hema says:

    Hi Jeff,

    Is there any work around to achieve the same in Windows Store app 8.0 ?

    Thanks,

    Hema

  2. Ado says:

    Hello Jeff,

    I tried the same without much luck. My HResult check returns 12037 which I handled.

    This is a combination of Expired & InvalidName.

    Basically my TransportInformation.ServerCertificate.Issuer does not equal theExpectedIssuer

    I have also ignored that check, but still couldn't get it working.

    Exception I get is:

    "The text associated with this error code could not be found.  The date in the certificate is invalid or has expired".

    Would you have any helpful hints?

    Also as a side-note. I will be trying to load the page in a WebView, is the approach still the same?  At the moment my WebView only shows a blank page when trying to open my HTTPS page.

    Kind Regards,

    Ado

  3. kartik patel says:

    Jeff,

    Thanks for the post – this is really useful. I am trying to do client cert auth whose root is not trusted. using ChainValidationResult.Untrusted i am able to bypass server trust but then it fails when client presents the cert with 403 – forbidden. do you know how to deal with that?

  4. blacklion9279 says:

    Thanks for the post – this is really useful. I am trying to do client cert auth whose root is not trusted. using ChainValidationResult.Untrusted i am able to bypass server trust but then it fails when client presents the cert with 403 – forbidden. do you know how to deal with that?

  5. Gigaplex says:

    This solution doesn't help us on Windows 7. We use self-signed certificates to encrypt RPC traffic on the local network, and as a result, our C# component can't interact with services not on the localhost. We need a solution that works on all supported Windows desktop platforms.

Skip to main content