using System;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using MQTTnet.Client;
namespace deviceSimulator
{
///
/// Verifies certificates against a list of manually trusted certs.
/// If a certificate is not in the Windows cert store, this will check that it's valid per our internal code.
///
internal class RootCertificateTrust
{
X509Certificate2Collection certificates;
internal RootCertificateTrust()
{
certificates = new X509Certificate2Collection();
}
///
/// Add a trusted certificate
///
///
internal void AddCert(X509Certificate2 x509Certificate2)
{
certificates.Add(x509Certificate2);
}
///
/// This matches the delegate signature expected for certificate verification for MQTTNet
///
///
///
internal bool VerifyServerCertificate(MqttClientCertificateValidationEventArgs arg) => VerifyServerCertificate(new object(), arg.Certificate, arg.Chain, arg.SslPolicyErrors);
///
/// This matches the delegate signature expected for certificate verification for M2MQTT
///
///
///
///
///
///
internal bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None) return true;
X509Chain chainNew = new X509Chain();
var chainTest = chain;
chainTest.ChainPolicy.ExtraStore.AddRange(certificates);
// Check all properties
chainTest.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
// This setup does not have revocation information
chainTest.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
// Build the chain
var buildResult = chainTest.Build(new X509Certificate2(certificate));
//Just in case it built with trust
if (buildResult) return true;
//If the error is something other than UntrustedRoot, fail
foreach (var status in chainTest.ChainStatus)
{
if (status.Status != X509ChainStatusFlags.UntrustedRoot)
{
return false;
}
}
//If the UntrustedRoot is on something OTHER than the GreenGrass CA, fail
foreach (var chainElement in chainTest.ChainElements)
{
foreach (var chainStatus in chainElement.ChainElementStatus)
{
if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot)
{
var found = certificates.Find(X509FindType.FindByThumbprint, chainElement.Certificate.Thumbprint, false);
if (found.Count == 0) return false;
}
}
}
return true;
}
}
}