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
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 https://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.
Comments
Anonymous
November 20, 2013
Hi Jeff, Is there any work around to achieve the same in Windows Store app 8.0 ? Thanks, HemaAnonymous
April 13, 2014
The comment has been removedAnonymous
April 08, 2015
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?Anonymous
April 08, 2015
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?Anonymous
September 23, 2015
The comment has been removed