internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback, ref ProtocolToken alertToken)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;
// We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true.
bool success = false;
X509Chain chain = null;
X509Certificate2 remoteCertificateEx = null;
try
{
X509Certificate2Collection remoteCertificateStore;
remoteCertificateEx = CertificateValidationPal.GetRemoteCertificate(_securityContext, out remoteCertificateStore);
_isRemoteCertificateAvailable = remoteCertificateEx != null;
if (remoteCertificateEx == null)
{
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, "(no remote cert)", !_remoteCertRequired);
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
}
else
{
chain = new X509Chain();
chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
if (remoteCertificateStore != null)
{
chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
}
sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties(
chain,
remoteCertificateEx,
_checkCertName,
_serverMode,
_hostName);
}
if (remoteCertValidationCallback != null)
{
success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors);
}
else
{
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired)
{
success = true;
}
else
{
success = (sslPolicyErrors == SslPolicyErrors.None);
}
}
if (NetEventSource.IsEnabled)
{
LogCertificateValidation(remoteCertValidationCallback, sslPolicyErrors, success, chain);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Cert validation, remote cert = {remoteCertificateEx}");
}
if (!success)
{
alertToken = CreateFatalHandshakeAlertToken(sslPolicyErrors, chain);
}
}
finally
{
// At least on Win2k server the chain is found to have dependencies on the original cert context.
// So it should be closed first.
if (chain != null)
{
chain.Dispose();
}
if (remoteCertificateEx != null)
{
remoteCertificateEx.Dispose();
}
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, success);
return success;
}