Click or drag to resize

Validation of server certificate

The topics in this section describe how to do a custom validation of a server certificate. The most secure way is when the server authenticates with a certificate that supports the chain trust. That means it must chain to a trusted root certificate authority. This is the case when the certificate is signed by a well-known certificate authority. But sometimes the server is using self-signed certificates which are not trusted by default. If you are working with modern .NET applications , consider using the HttpClient class (introduced in .Net 4.5) for making HTTP requests. It provides a more flexible and secure way to handle certificate validation. Regularly update certificate validation logic: stay informed about changes in security best practices and update your certificate validation logic accordingly. Periodically review and update your custom validation callback as needed. In general follow these steps:

  • Implement a custom certificate validation callback method.

  • Attach the custom validation callback to the specific request.

  • Validate certificates and handle errors within the callback.

  • Dispose of resources properly to prevent leaks.

Guidelines
Security note  Security Note

DO NOT use ServicePointManager.ServerCertificateValidationCallback inside BVMS scripts. The whole BVMS application (Operator Client or Management Server) would always use this callback when validating certificates. By using this global callback you will introduce potential security risks.

Security note  Security Note

DO NOT return always true when using ServicePointManager.ServerCertificateValidationCallback because by default any certificate will pass validation for all outgoing HTTPS requests.

C#
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslErrors) => { return true; };

Security note  Security Note

DO use HttpClientHandler.ServerCertificateCustomValidationCallback or WebRequestHandler.ServerCertificateValidationCallback because it validates only the specific request and the corresponding server certificate.

C#
internal class CertificateValidationExample
{
    public async void UseHttpClientHandler()
    {
        try
        {
            using var handler = new HttpClientHandler();

            // Set custom server validation callback
            handler.ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation;

            // WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.
            using var client = new HttpClient(handler);

            var response = await client.GetAsync("www.bosch.com");
            var content = await response.Content.ReadAsStringAsync();
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine("Exception Caught!");
            Console.WriteLine("Message :{0} ", e.Message);
        }
    }

    private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2? certificate, X509Chain? chain, SslPolicyErrors sslErrors)
    {
        // Add your certificate validation logic here.
        // For example, you can compare the certificate's thumbprint or subject to expected values.
        // If the certificate is valid according to your criteria, return true; otherwise, return false.

        return requestMessage.RequestUri.Host == "www.bosch.com"
            && certificate != null 
            && certificate.Thumbprint == "88281e823a4671e282fc9dfe162fcf4f2109ba65"
            && sslErrors == SslPolicyErrors.RemoteCertificateChainErrors;
    }

    public async void UseWebRequestHandler()
    {
        try
        {
            using var handler = new WebRequestHandler();

            // Set custom server validation callback
            handler.ServerCertificateValidationCallback = ServerCertificateValidation;

            // WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.
            using var client = new HttpClient(handler);

            var response = await client.GetAsync("www.bosch.com");
            var content = await response.Content.ReadAsStringAsync();
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine("Exception Caught!");
            Console.WriteLine("Message :{0} ", e.Message);
        }
    }

    private bool ServerCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslErrors)
    {
        // Add your certificate validation logic here.
        // For example, you can compare the certificate's thumbprint or subject to expected values.
        // If the certificate is valid according to your criteria, return true; otherwise, return false.

        return sender is HttpWebRequest httpWebRequest
            && httpWebRequest.RequestUri.Host == "www.bosch.com"
            && certificate is X509Certificate2 x509Certificate2
            && x509Certificate2.Thumbprint == "88281e823a4671e282fc9dfe162fcf4f2109ba65"
            && sslErrors == SslPolicyErrors.RemoteCertificateChainErrors;
    }
}

Security note  Security Note

AVOID to use HttpWebRequest because it is deprecated.

AVOID to use ServicePointManager.ServerCertificateValidationCallback in the BVMS SDK Application because it is a static callback which handles validation globally for every connection in the application. When you must use the ServicePointManager.ServerCertificateValidationCallback , validate specific certificate for the specific host.

C#
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

class ValidationClass
{

    public void Subscribe()
    {
        string serverUrl = "https://www.bosch.com/";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverUrl);
        ServicePointManager.ServerCertificateValidationCallback += ServerCertificateValidation;
    }

    private static bool ServerCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslErrors)
    {
        if (sslErrors == SslPolicyErrors.None)
        {
            return true;
        }

        // Validate the specific certificate for the HTTPS requests to the specific host.
        // Add your certificate validation logic here.
        // For example, you can compare the certificate's thumbprint or subject to expected values.
        // If the certificate is valid according to your criteria, return true; otherwise, return false.

        return sender is HttpWebRequest httpWebRequest
                && httpWebRequest.RequestUri.Host == "www.bosch.com"
                && certificate is X509Certificate2 x509Certificate2
                && x509Certificate2.Thumbprint == "88281e823a4671e282fc9dfe162fcf4f2109ba65"
                && sslErrors == SslPolicyErrors.RemoteCertificateChainErrors;
    }
}