Skip to content

Instantly share code, notes, and snippets.

@JBirdVegas
Created September 23, 2020 15:24
Show Gist options
  • Save JBirdVegas/a9abc62d8e9d41698f271530013c6879 to your computer and use it in GitHub Desktop.
Save JBirdVegas/a9abc62d8e9d41698f271530013c6879 to your computer and use it in GitHub Desktop.
Certificate pinning example using C#
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
namespace CertificatePinningTutorial
{
internal class Program
{
private readonly string _domain;
private Program(string domain)
{
_domain = domain;
}
private String GetSha1ThumbprintFromApi()
{
ServicePointManager.ServerCertificateValidationCallback = null;
var requestUriString = $"https://api.cert.ist/{_domain}";
WebRequest request = WebRequest.Create(requestUriString);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream()!);
CertIstApi certIstApi = JsonSerializer.Deserialize<CertIstApi>(reader.ReadToEnd());
return certIstApi.certificate.hashes.sha1;
}
private void ValidateDomain()
{
try
{
WebRequest.DefaultWebProxy = null;
ServicePointManager.ServerCertificateValidationCallback = PinPublicKey;
WebRequest wr = WebRequest.Create($"https://{_domain}");
wr.GetResponse();
}
catch (WebException)
{
Environment.Exit(1);
}
}
// ReSharper disable once UnusedParameter.Global
public static void Main(string[] _)
{
new Program("wordpress.com").ValidateDomain();
new Program("urip.com").ValidateDomain();
new Program("xkcd.com").ValidateDomain();
new Program("cert.ist").ValidateDomain();
}
private bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
var keyDerFromApis = GetSha1ThumbprintFromApi();
if (null == certificate)
{
return false;
}
var cert = new X509Certificate2(certificate);
var isPinnedThumbprintValid =
cert.Thumbprint != null && cert.Thumbprint.ToLower().Equals(keyDerFromApis.ToLower());
Console.WriteLine($"{_domain} certificate sha1 from api: {keyDerFromApis}, is valid: {isPinnedThumbprintValid}");
return isPinnedThumbprintValid;
}
}
}
// this is the minimum we can deserialize to pin the certificate
// ReSharper disable once ClassNeverInstantiated.Global
public class CertIstApiKeyStats
{
// ReSharper disable once UnusedAutoPropertyAccessor.Global
// ReSharper disable once InconsistentNaming
public CertIstApiHashes hashes { get; set; }
}
// ReSharper disable once ClassNeverInstantiated.Global
public class CertIstApi
{
// ReSharper disable once UnusedAutoPropertyAccessor.Global
// ReSharper disable once InconsistentNaming
public CertIstApiKeyStats certificate { get; set; }
}
// ReSharper disable once ClassNeverInstantiated.Global
public class CertIstApiHashes
{
// ReSharper disable once UnusedAutoPropertyAccessor.Global
// ReSharper disable once InconsistentNaming
public string sha1 { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment