Created
February 6, 2019 22:37
-
-
Save jpda/3d503086047fee05c4730c28a53633d6 to your computer and use it in GitHub Desktop.
ca-verify
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Net.Security; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace HttpPrivateCa | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var a = new ApiCaller(); | |
a.MakeRequest().Wait(); | |
Console.ReadLine(); | |
} | |
} | |
public class ApiCaller | |
{ | |
private readonly HttpClient _client; | |
public ApiCaller() | |
{ | |
var handler = new HttpClientHandler | |
{ | |
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => | |
{ | |
return VerifyServerCert(this, cert, chain, errors); | |
} | |
}; | |
_client = new HttpClient(handler); | |
} | |
public async Task MakeRequest() | |
{ | |
var d = await _client.GetAsync("https://badssl.jpd.ms/"); | |
Console.WriteLine($"{await d.Content.ReadAsStringAsync()}"); | |
} | |
//see https://stackoverflow.com/questions/6497040/how-do-i-validate-that-a-certificate-was-created-by-a-particular-certification-a | |
static bool VerifyServerCert(object sender, X509Certificate2 certificate, X509Chain chainorigin, SslPolicyErrors sslPolicyErrors) | |
{ | |
X509Chain chain = new X509Chain(); | |
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; | |
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; | |
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; | |
chain.ChainPolicy.VerificationTime = DateTime.Now; | |
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 0); | |
// This part is very important. You're adding your known root here. | |
// It doesn't have to be in the computer store at all. Neither certificates do. | |
String CA_FILE = @"..\..\..\myca.cer"; | |
X509Certificate2 authority = new X509Certificate2(CA_FILE); | |
chain.ChainPolicy.ExtraStore.Add(authority); | |
bool isChainValid = chain.Build(certificate); | |
if (!isChainValid) | |
{ | |
string[] errors = chain.ChainStatus | |
.Select(x => string.Format("{0} ({1})", x.StatusInformation.Trim(), x.Status)) | |
.ToArray(); | |
string certificateErrorsString = "Unknown errors."; | |
if (errors != null && errors.Length > 0) | |
{ | |
certificateErrorsString = String.Join(", ", errors); | |
} | |
throw new Exception("Trust chain did not complete to the known authority anchor. Errors: " + certificateErrorsString); | |
} | |
// This piece makes sure it actually matches your known root | |
var valid = chain.ChainElements | |
.Cast<X509ChainElement>() | |
.Any(x => x.Certificate.Thumbprint == authority.Thumbprint); | |
if (!valid) | |
{ | |
throw new Exception("Trust chain did not complete to the known authority anchor. Thumbprints did not match."); | |
} | |
return valid; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment