CertificateValidationCallback Delegate

Represents the method that handles the validation of a remote certificate. This delegate is used by the SslStream class.

Syntax

public delegate bool CertificateValidationCallback(
    object sender,
    System.Security.Cryptography.X509Certificates.X509Certificate certificate,
    System.Security.Cryptography.X509Certificates.X509Chain chain,
    System.Net.Security.SslPolicyErrors sslPolicyErrors
);

Parameters

Parameter Description
sender The object that initiated the callback. This is typically an SslStream object.
certificate An X509Certificate object that represents the remote certificate used to authenticate the server.
chain An X509Chain object that represents the certificate chain associated with the remote certificate.
sslPolicyErrors A bitwise combination of the SslPolicyErrors values that result from server certificate validation.

Return Value

true if the certificate is accepted; otherwise, false.

Remarks

The CertificateValidationCallback delegate is used to provide custom certificate validation logic for SSL/TLS connections. When an SslStream attempts to establish a secure connection, it performs a series of default validation steps on the server's certificate. If any of these default checks fail, or if you want to implement additional checks, you can assign a method to the RemoteCertificateValidationCallback property of the SslStream.

The callback method receives the remote certificate, the certificate chain, and any SSL policy errors that occurred during the default validation. Your custom logic can then inspect these parameters and decide whether to trust the certificate.

If your callback returns true, the connection is allowed to proceed despite any SslPolicyErrors that might have occurred. If it returns false, the connection is aborted.

Important: Implementing custom certificate validation requires careful consideration of security implications. Improperly validating certificates can expose your application to man-in-the-middle attacks. Always ensure your validation logic is robust and follows best practices for certificate validation.

The sslPolicyErrors parameter provides valuable information about why the default validation might have failed. Common errors include:

  • RemoteCertificateChainErrors: The certificate chain is invalid.
  • RemoteCertificateNameMismatch: The certificate's subject name does not match the server's hostname.
  • RemoteCertificateNotAvailable: The server did not provide a certificate.

You can check for specific errors using bitwise operations:


if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
    // Handle name mismatch
}
                

Example

The following example demonstrates how to create a custom validation callback that accepts any certificate, which is generally not recommended for production environments. This is for illustrative purposes only.


using System;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

public class SslClientExample
{
    public static async Task ConnectAsync(string host, int port)
    {
        using (var client = new TcpClient(host, port))
        using (var sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null))
        {
            try
            {
                // The server name is the name of the server that the client is connecting to.
                await sslStream.AuthenticateAsClientAsync(host);

                // Do work with the sslStream.
                Console.WriteLine("SSL connection established.");
                // ... send and receive data ...
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Authentication failed: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                return;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }
    }

    // Custom certificate validation callback.
    // In a real-world scenario, you would implement more robust validation logic.
    public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        if (sslPolicyErrors == SslPolicyErrors.None)
        {
            // Server certificate is trusted.
            return true;
        }

        // The following code demonstrates a trust-all approach.
        // THIS IS NOT SECURE AND SHOULD NOT BE USED IN PRODUCTION.
        Console.WriteLine($"SSL Policy Errors: {sslPolicyErrors}");
        Console.WriteLine("Warning: Accepting server certificate despite policy errors.");
        return true; // In production, you would validate the certificate more thoroughly.
    }

    public static async Task Main(string[] args)
    {
        // Example usage:
        // await ConnectAsync("example.com", 443);
        Console.WriteLine("This is an example of how to use CertificateValidationCallback.");
        Console.WriteLine("In a real application, replace 'example.com' with the target server.");
    }
}
                

Requirements

Assembly Framework
System.Net.Primitives.dll .NET Standard 2.0, .NET Core 2.0, .NET Framework 4.6.1
System.dll .NET Framework 2.0, 3.0, 3.5, 4.0, 4.5