如何在 X509Chain 上打印有用的调试信息?
How to print useful debug info on an X509Chain?
X509Certificate
class 有一个 ToString()
方法可以漂亮地打印所有有用的细节...... X509Chain
class 没有。
我 运行 进入相当通用的 SslPolicyErrors
:RemoteCertificateChainErrors
。但是,我不知道从链中打印什么有助于调试。
documentation显示了很多元素遍历和打印。但是,我很困惑……我应该打印每个 ChainElement 的 ChainStatus,就像它们显示的那样,还是打印顶级 ChainStatus?
我想我会用扩展方法将其包装起来...我需要打印哪些信息才能进行调试 RemoteCertificateChainErrors
?
究竟是什么错误取决于解释(链中的证书之一可能无效或者您的主机可能不信任其中一个证书),但如果没有证书和状态,您将走不远来自每个元素。
这里有一些扩展方法,我用它来漂亮地打印来自链对象的有用调试信息。
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public static class X509Extensions
{
public static string ToDisplayString(this X509Chain chain)
{
var b = new StringBuilder();
b.AppendLine($"[{nameof(chain.ChainPolicy.RevocationFlag)}]");
b.AppendLine($" {chain.ChainPolicy.RevocationFlag}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.RevocationMode)}]");
b.AppendLine($" {chain.ChainPolicy.RevocationMode}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.VerificationFlags)}]");
b.AppendLine($" {chain.ChainPolicy.VerificationFlags}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.VerificationTime)}]");
b.AppendLine($" {chain.ChainPolicy.VerificationTime}");
b.AppendLine();
b.AppendLine($"[Application Policy]");
foreach (var policy in chain.ChainPolicy.ApplicationPolicy)
{
b.AppendLine($" {policy.ToDisplayString()}");
}
b.AppendLine();
b.AppendLine($"[Certificate Policy]");
foreach (var policy in chain.ChainPolicy.CertificatePolicy)
{
b.AppendLine($" {policy.ToDisplayString()}");
}
b.AppendLine();
b.AppendLine($"[Elements]");
foreach (var (element, index) in chain.ChainElements.Cast<X509ChainElement>().Select((element, index) => (element, index)))
{
b.AppendLine();
b.AppendLine($"[Element {index + 1}]");
b.AppendLine();
b.Append(element.Certificate.ToString());
b.AppendLine();
b.AppendLine($"[Status]");
foreach (var status in element.ChainElementStatus)
{
b.AppendLine($" {status.ToDisplayString()}");
}
}
return b.ToString();
}
public static string ToDisplayString(this Oid oid)
{
return oid.FriendlyName == oid.Value
? $"{oid.Value}"
: $"{oid.FriendlyName}: {oid.Value}";
}
public static string ToDisplayString(this X509ChainStatus status)
{
return $"{status.Status}: {status.StatusInformation}";
}
}
您可以从任何远程证书验证回调中调用它。
bool CertificateValidationCallback(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors)
{
if (errors == SslPolicyErrors.None)
{
return true;
}
logger.LogError($"SSL Policy Error(s): {1}", errors);
logger.LogError($"X509 Certificate:{0}{1}", Environment.NewLine, certificate.ToString());
logger.LogError($"X509 Chain:{0}{1}", Environment.NewLine, chain.ToDisplayString());
return false;
}
X509Certificate
class 有一个 ToString()
方法可以漂亮地打印所有有用的细节...... X509Chain
class 没有。
我 运行 进入相当通用的 SslPolicyErrors
:RemoteCertificateChainErrors
。但是,我不知道从链中打印什么有助于调试。
documentation显示了很多元素遍历和打印。但是,我很困惑……我应该打印每个 ChainElement 的 ChainStatus,就像它们显示的那样,还是打印顶级 ChainStatus?
我想我会用扩展方法将其包装起来...我需要打印哪些信息才能进行调试 RemoteCertificateChainErrors
?
究竟是什么错误取决于解释(链中的证书之一可能无效或者您的主机可能不信任其中一个证书),但如果没有证书和状态,您将走不远来自每个元素。
这里有一些扩展方法,我用它来漂亮地打印来自链对象的有用调试信息。
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public static class X509Extensions
{
public static string ToDisplayString(this X509Chain chain)
{
var b = new StringBuilder();
b.AppendLine($"[{nameof(chain.ChainPolicy.RevocationFlag)}]");
b.AppendLine($" {chain.ChainPolicy.RevocationFlag}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.RevocationMode)}]");
b.AppendLine($" {chain.ChainPolicy.RevocationMode}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.VerificationFlags)}]");
b.AppendLine($" {chain.ChainPolicy.VerificationFlags}");
b.AppendLine();
b.AppendLine($"[{nameof(chain.ChainPolicy.VerificationTime)}]");
b.AppendLine($" {chain.ChainPolicy.VerificationTime}");
b.AppendLine();
b.AppendLine($"[Application Policy]");
foreach (var policy in chain.ChainPolicy.ApplicationPolicy)
{
b.AppendLine($" {policy.ToDisplayString()}");
}
b.AppendLine();
b.AppendLine($"[Certificate Policy]");
foreach (var policy in chain.ChainPolicy.CertificatePolicy)
{
b.AppendLine($" {policy.ToDisplayString()}");
}
b.AppendLine();
b.AppendLine($"[Elements]");
foreach (var (element, index) in chain.ChainElements.Cast<X509ChainElement>().Select((element, index) => (element, index)))
{
b.AppendLine();
b.AppendLine($"[Element {index + 1}]");
b.AppendLine();
b.Append(element.Certificate.ToString());
b.AppendLine();
b.AppendLine($"[Status]");
foreach (var status in element.ChainElementStatus)
{
b.AppendLine($" {status.ToDisplayString()}");
}
}
return b.ToString();
}
public static string ToDisplayString(this Oid oid)
{
return oid.FriendlyName == oid.Value
? $"{oid.Value}"
: $"{oid.FriendlyName}: {oid.Value}";
}
public static string ToDisplayString(this X509ChainStatus status)
{
return $"{status.Status}: {status.StatusInformation}";
}
}
您可以从任何远程证书验证回调中调用它。
bool CertificateValidationCallback(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors)
{
if (errors == SslPolicyErrors.None)
{
return true;
}
logger.LogError($"SSL Policy Error(s): {1}", errors);
logger.LogError($"X509 Certificate:{0}{1}", Environment.NewLine, certificate.ToString());
logger.LogError($"X509 Chain:{0}{1}", Environment.NewLine, chain.ToDisplayString());
return false;
}