RemoteCertificateValidationCallback Delegate
public delegate bool RemoteCertificateValidationCallback(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors);
Represents a method that validates a server's X.509 certificate.
The RemoteCertificateValidationCallback delegate is used to provide a custom validation procedure for the server certificate during an SSL/TLS connection. When a client connects to a server using a protocol that relies on SSL/TLS (like HTTPS), the server presents its certificate. The default validation process checks if the certificate is trusted, has not expired, and matches the hostname. However, in certain scenarios, you might need to implement more specific or lenient validation logic. This delegate allows you to hook into that process and return your own decision on whether the certificate is acceptable.
Syntax
public delegate bool RemoteCertificateValidationCallback(
object sender,
X509Certificate? certificate,
X509Chain? chain,
SslPolicyErrors sslPolicyErrors
);
Parameters
| Parameter | Description |
|---|---|
sender |
The object that initiated the callback. This is typically an instance of System.Net.Security.SslStream. |
certificate |
The X.509 certificate that was presented by the server. This can be null if the server did not provide a certificate. |
chain |
The chain of certificates, built from the server certificate up to a trusted root. This can be null if the server did not provide a certificate or if certificate chain building failed. |
sslPolicyErrors |
A bitwise combination of enumeration values that specifies the errors encountered during certificate validation. |
Return Value
true if the certificate is valid and the connection should proceed; otherwise, false.
Remarks
The RemoteCertificateValidationCallback delegate is assigned to the RemoteCertificateValidationCallback property of the System.Net.Security.SslStream class. When an SSL/TLS connection is established, and the server presents its certificate, the SslStream invokes the callback method.
Inside your callback implementation, you should inspect the provided parameters:
certificate: Check if it's the expected certificate, perhaps by examining its subject name, issuer, or thumbprint.chain: You can traverse the chain to verify trust anchors or check for specific intermediate certificates.sslPolicyErrors: This parameter is crucial. It indicates any errors that the default validation process has already detected. You might choose to ignore certain errors (e.g., certificate expiration if you are in a controlled test environment) but should generally be cautious when doing so.
If your callback returns true, the SSL/TLS handshake continues. If it returns false, the handshake fails, and the connection is terminated.
Example
The following example demonstrates how to use a custom RemoteCertificateValidationCallback to allow connections even if the server certificate has SSL policy errors (e.g., self-signed certificates in a test environment). This is not recommended for production use.
using System;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public class SslClient
{
public static async Task ConnectAsync(string host, int port)
{
using (var client = new TcpClient())
{
await client.ConnectAsync(host, port);
using (var sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate))
{
try
{
// Authenticate as client
await sslStream.AuthenticateAsClientAsync(host);
// Read/Write data...
Console.WriteLine("SSL connection established successfully.");
}
catch (Exception ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
}
}
}
}
// Custom validation callback - WARNING: Insecure for production!
public static bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
{
Console.WriteLine($"Certificate validation errors: {sslPolicyErrors}");
// In a real application, you would perform more robust checks here.
// For demonstration purposes, we'll allow connections even if there are errors.
// NEVER do this in production code without extremely careful consideration.
if (sslPolicyErrors == SslPolicyErrors.None)
{
return true; // Certificate is valid
}
// Example: Accept self-signed certificates or certificates with other issues
// if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) ||
// sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
// {
// // Log the issue and decide if it's acceptable in your context
// Console.WriteLine("Warning: Allowing connection despite certificate errors.");
// return true; // For demonstration, accept these errors
// }
// For this example, we will simply return true to allow the connection regardless of errors.
// This is HIGHLY INSECURE and should not be used in production.
Console.WriteLine("Accepting certificate despite potential policy errors (INSECURE).");
return true;
}
// Example usage:
// public static async Task Main(string[] args)
// {
// // Replace with a real server host and port that uses SSL/TLS
// // await ConnectAsync("your.ssl.server.com", 443);
// }
}