Custom X509CertificateValidator with TLS 1.2

Colm de Cleir 136 Reputation points
2022-01-24T15:53:15.877+00:00

I'm having a problem with a custom certificate validator when using TLS 1.2

I have set up a custom validator by inheriting from X509CertificateValidator and implementing the Validate() function.

However, for some reason Validate() function never gets called, and my client gets the error:

The caller was not authenticated by the service

The inner exception:

The request for security token could not be satisfied because authentication failed.

This works fine with TLS 1.0 (with that enabled, I can set a breakpoint in Validate() and it gets hit, but disabled, it doesn't.)

As advised by other questions, I have tried adding this both in the client and the server:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

...and this in the client's config file:

<AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false;;Switch.System.Net.DontEnableSystemDefaultTlsVersions=false" />

... and this in the server's web.config file:

<add key="AppContext.SetSwitch:Switch.System.Net.DontEnableSchUseStrongCrypto" value="false" /> <add key="AppContext.SetSwitch:Switch.System.Net.DontEnableSystemDefaultTlsVersions" value="false" />

Here is the code that creates the custom validator:

protected override void ApplyConfiguration()   // Overrides ServiceHost.ApplyConfiguration()
{

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    base.ApplyConfiguration();

    var binding = new MyAppHttpBinding();    // Custom object inheriting from CustomBinding - See below...

    AddServiceEndpoint(typeof(IMyService), binding);

    Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;

    var configuration = WebConfigurationManager.OpenWebConfiguration("~");
    var clientCertificate = configuration.GetCertificate("MyApp.ClientCertificate");
    var serviceCertificate = configuration.GetCertificate("MyApp.ServerCertificate");

    Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new ThumbprintCertificateValidator(new[] { clientCertificate });
    Credentials.ServiceCertificate.Certificate = serviceCertificate;
}

... and the Validate() function...

(Doesn't appear to hit this with just TLS 1.2)

    public void Validate(string thumbprint)
    {
        var valid = Thumbprints
            .Contains(thumbprint);

        if (!valid)
        {
            throw new SecurityTokenValidationException("Certificate thumbprint does not match any in certificate store.");
        }
    }

    /// <summary>
    /// Validates the certificate's thumbprint with those specified.
    /// </summary>
    public override void Validate(X509Certificate2 certificate)
    {
        var thumbprint = certificate.Thumbprint;

        Validate(thumbprint);
    }`

Here is the initialisation code for MyAppHttpBinding called from its constructor

    var sslNegotiationBindingElement = SecurityBindingElement.CreateSslNegotiationBindingElement(true);

    sslNegotiationBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;

    var secureConversationBindingElement = SecurityBindingElement.CreateSecureConversationBindingElement(sslNegotiationBindingElement);

    Elements.Add(new TransactionFlowBindingElement());
    Elements.Add(secureConversationBindingElement);
    Elements.Add(new TextMessageEncodingBindingElement());
    Elements.Add(new HttpTransportBindingElement());
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,400 questions
0 comments No comments
{count} votes

Accepted answer
  1. Lan Huang-MSFT 25,866 Reputation points Microsoft Vendor
    2022-01-25T07:46:49.237+00:00

    Hi @Colm de Cleir ,
    To use TLS, see the documentation Transport Layer Security (TLS) best practice with the .NET Framework.

    1. For TLS 1.2, target .NET Framework 4.7 or higher on your application and .NET Framework 4.7.1 or higher on your WCF application.
      In the example below, replace 4.7.2 with whatever version of the framework you are currently using >= 4.7 <system.web>
      <compilation targetFramework="4.7.2"></compilation>
      <httpRuntime targetFramework="4.7.2" />
      </system.web>

    2.It is recommended not to specify the TLS version. Configure your code to let the OS decide the TLS version.
    3.One more symbol (;) is written in the screenshot code, and the configuration of the client and server should be as consistent as possible.
    168175-1.png
    Best regards,
    Lan Huang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful